All of lore.kernel.org
 help / color / mirror / Atom feed
From: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
To: Jacopo Mondi <jacopo@jmondi.org>
Cc: Steve Longerbeam <slongerbeam@gmail.com>,
	sakari.ailus@iki.fi, hverkuil-cisco@xs4all.nl,
	mirela.rabulea@nxp.com, xavier.roumegue@oss.nxp.com,
	tomi.valkeinen@ideasonboard.com, hugues.fruchet@st.com,
	prabhakar.mahadev-lad.rj@bp.renesas.com, aford173@gmail.com,
	festevam@gmail.com, Eugen.Hristev@microchip.com,
	jbrunet@baylibre.com, Mauro Carvalho Chehab <mchehab@kernel.org>,
	linux-media@vger.kernel.org
Subject: Re: [PATCH 06/21] media: ov5640: Rework CSI-2 clock tree
Date: Tue, 1 Feb 2022 19:27:31 +0200	[thread overview]
Message-ID: <YfltgzUdzbQjmLyt@pendragon.ideasonboard.com> (raw)
In-Reply-To: <20220131143245.128089-7-jacopo@jmondi.org>

Hi Jacopo,

Thank you for the patch.

On Mon, Jan 31, 2022 at 03:32:30PM +0100, Jacopo Mondi wrote:
> Re-work the ov5640_set_mipi_pclk() function to calculate the
> PLL configuration using the pixel_rate and link_freq values set at
> s_fmt time.
> 
> Rework the DVP clock mode settings to calculate the pixel clock
> internally and remove the assumption on the 16bpp format.
> 
> Tested in MIPI CSI-2 mode with 2 data lanes with:
> - all the sensor supported resolutions in UYVY and RGB565 formats.
> - resolutions >= 1280x720 in RAW Bayer format.
> - resolutions < 1280x720 in RGB888 format.
> 
> Signed-off-by: Jacopo Mondi <jacopo@jmondi.org>
> 
> ---
> 
> Not tested with JPEG.
> Not tested with 1 data lane.
> Not tested in DVP mode.
> 
> If I get come Tested-by: tags for the above use cases, it would be
> great.
> ---
>  drivers/media/i2c/ov5640.c | 175 ++++++++++++++++++++-----------------
>  1 file changed, 94 insertions(+), 81 deletions(-)
> 
> diff --git a/drivers/media/i2c/ov5640.c b/drivers/media/i2c/ov5640.c
> index 457f76030163..acc636500907 100644
> --- a/drivers/media/i2c/ov5640.c
> +++ b/drivers/media/i2c/ov5640.c
> @@ -29,6 +29,8 @@
>  #define OV5640_XCLK_MIN  6000000
>  #define OV5640_XCLK_MAX 54000000
>  
> +#define OV5640_LINK_RATE_MAX	490000000U
> +
>  #define OV5640_DEFAULT_SLAVE_ID 0x3c
>  
>  #define OV5640_REG_SYS_RESET02		0x3002
> @@ -88,6 +90,7 @@
>  #define OV5640_REG_POLARITY_CTRL00	0x4740
>  #define OV5640_REG_MIPI_CTRL00		0x4800
>  #define OV5640_REG_DEBUG_MODE		0x4814
> +#define OV5640_REG_PCLK_PERIOD		0x4837
>  #define OV5640_REG_ISP_FORMAT_MUX_CTRL	0x501f
>  #define OV5640_REG_PRE_ISP_TEST_SET1	0x503d
>  #define OV5640_REG_SDE_CTRL0		0x5580
> @@ -1035,69 +1038,80 @@ static unsigned long ov5640_calc_sys_clk(struct ov5640_dev *sensor,
>   * ov5640_set_mipi_pclk() - Calculate the clock tree configuration values
>   *			    for the MIPI CSI-2 output.
>   *
> - * @rate: The requested bandwidth per lane in bytes per second.
> - *	  'Bandwidth Per Lane' is calculated as:
> - *	  bpl = HTOT * VTOT * FPS * bpp / num_lanes;
> - *
> - * This function use the requested bandwidth to calculate:
> - * - sample_rate = bpl / (bpp / num_lanes);
> - *	         = bpl / (PLL_RDIV * BIT_DIV * PCLK_DIV * MIPI_DIV / num_lanes);
> - *
> - * - mipi_sclk   = bpl / MIPI_DIV / 2; ( / 2 is for CSI-2 DDR)

It would be useful to have the update formula either here or in the code
below.

> - *
> - * with these fixed parameters:
> - *	PLL_RDIV	= 2;
> - *	BIT_DIVIDER	= 2; (MIPI_BIT_MODE == 8 ? 2 : 2,5);
> - *	PCLK_DIV	= 1;
> - *
> - * The MIPI clock generation differs for modes that use the scaler and modes
> - * that do not. In case the scaler is in use, the MIPI_SCLK generates the MIPI
> - * BIT CLk, and thus:
> - *
> - * - mipi_sclk = bpl / MIPI_DIV / 2;
> - *   MIPI_DIV = 1;
> - *
> - * For modes that do not go through the scaler, the MIPI BIT CLOCK is generated
> - * from the pixel clock, and thus:
> - *
> - * - sample_rate = bpl / (bpp / num_lanes);
> - *	         = bpl / (2 * 2 * 1 * MIPI_DIV / num_lanes);
> - *		 = bpl / (4 * MIPI_DIV / num_lanes);
> - * - MIPI_DIV	 = bpp / (4 * num_lanes);
> - *
> - * FIXME: this have been tested with 16bpp and 2 lanes setup only.
> - * MIPI_DIV is fixed to value 2, but it -might- be changed according to the
> - * above formula for setups with 1 lane or image formats with different bpp.
> - *
> - * FIXME: this deviates from the sensor manual documentation which is quite
> - * thin on the MIPI clock tree generation part.
> + * FIXME: tested with 2 lanes only.
>   */
> -static int ov5640_set_mipi_pclk(struct ov5640_dev *sensor,
> -				unsigned long rate)
> +static int ov5640_set_mipi_pclk(struct ov5640_dev *sensor)
>  {
> -	const struct ov5640_mode_info *mode = sensor->current_mode;
> +	u8 bit_div, mipi_div, pclk_div, sclk_div, sclk2x_div, root_div;
> +	struct v4l2_mbus_framefmt *fmt = &sensor->fmt;
>  	u8 prediv, mult, sysdiv;
> -	u8 mipi_div;
> +	unsigned long sysclk;
> +	unsigned long sample_rate;
> +	u8 pclk_period;
> +	s64 link_freq;
>  	int ret;
>  
> +	/* Use the link frequency computed at s_fmt time. */
> +	link_freq = ov5640_csi2_link_freqs[sensor->ctrls.link_freq->cur.val];
> +
>  	/*
> -	 * 1280x720 is reported to use 'SUBSAMPLING' only,
> -	 * but according to the sensor manual it goes through the
> -	 * scaler before subsampling.
> +	 * - mipi_div - Additional divider for the MIPI lane clock.
> +	 *
> +	 * Higher link frequencies would make sysclk > 1GHz.
> +	 * Keep the sysclk low and do not divide in the MIPI domain.
>  	 */
> -	if (mode->dn_mode == SCALING ||
> -	   (mode->id == OV5640_MODE_720P_1280_720))
> -		mipi_div = OV5640_MIPI_DIV_SCLK;
> +	if (link_freq > OV5640_LINK_RATE_MAX)
> +		mipi_div = 1;
>  	else
> -		mipi_div = OV5640_MIPI_DIV_PCLK;
> +		mipi_div = 2;
>  
> -	ov5640_calc_sys_clk(sensor, rate, &prediv, &mult, &sysdiv);
> +	sysclk = link_freq * mipi_div;
> +	ov5640_calc_sys_clk(sensor, sysclk, &prediv, &mult, &sysdiv);
>  
> -	ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL0,
> -			     0x0f, OV5640_PLL_CTRL0_MIPI_MODE_8BIT);
> +	/*
> +	 * Adjust PLL parameters to maintain the MIPI_SCLK-to-PCLK ratio;
> +	 *
> +	 * - root_div = 2 (fixed)
> +	 * - bit_div : MIPI 8-bit = 2
> +	 *	       MIPI 10-bit = 2,5

s/2,5/2.5/

> +	 * - pclk_div = 1 (fixed)
> +	 * - pll_div  = (2 lanes ? mipi_div : 2 * mipi_div)

What's pll_div here ? There's no corresponding variable. It would be
nice to name it according to the clock tree diagram located above in the
driver.

> +	 *   2 lanes: MIPI_SCLK = (4 or 5) * PCLK
> +	 *   1 lanes: MIPI_SCLK = (8 or 10) * PCLK
> +	 *
> +	 * TODO: support 10-bit formats
> +	 * TODO: test with 1 data lane
> +	 */
> +	root_div = OV5640_PLL_CTRL3_PLL_ROOT_DIV_2;
> +	bit_div =  OV5640_PLL_CTRL0_MIPI_MODE_8BIT;
> +	pclk_div = OV5640_PLL_SYS_ROOT_DIVIDER_BYPASS;
>  
> -	ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL1,
> -			     0xff, sysdiv << 4 | mipi_div);
> +	/*
> +	 * Scaler clock:
> +	 * - YUV: PCLK >= 2 * SCLK
> +	 * - RAW or JPEG: PCLK >= SCLK
> +	 * - sclk2x_div = sclk_div / 2
> +	 *
> +	 * TODO: test with JPEG.
> +	 */
> +	sclk_div = ilog2(OV5640_SCLK_ROOT_DIV);
> +	sclk2x_div = ilog2(OV5640_SCLK2X_ROOT_DIV);
> +
> +	/*
> +	 * Set the sample period expressed in ns with 1-bit decimal
> +	 * (0x01=0.5ns).
> +	 */
> +	sample_rate = ov5640_pixel_rates[sensor->current_mode->pixel_rate]
> +		    * (ov5640_code_to_bpp(fmt->code) / 8);

Won't this cause rouding errors for bpp values that are not multiples of
8 ?

> +	pclk_period = 2000000000U / sample_rate;
> +
> +	/* Program the clock tree registers. */
> +	ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL0, 0x0f, bit_div);
> +	if (ret)
> +		return ret;
> +
> +	ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL1, 0xff,
> +			     sysdiv << 4 | mipi_div);

Here you don't use parentheses around (sysdiv << 4), and below you do
when writing OV5640_REG_SYS_ROOT_DIVIDER. They're not necessary, but it
could be clearer to add parentheses here.

>  	if (ret)
>  		return ret;
>  
> @@ -1105,13 +1119,27 @@ static int ov5640_set_mipi_pclk(struct ov5640_dev *sensor,
>  	if (ret)
>  		return ret;
>  
> -	ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL3,
> -			     0x1f, OV5640_PLL_CTRL3_PLL_ROOT_DIV_2 | prediv);
> +	ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL3, 0x1f,
> +			     root_div | prediv);
>  	if (ret)
>  		return ret;
>  
> -	return ov5640_mod_reg(sensor, OV5640_REG_SYS_ROOT_DIVIDER,
> -			      0x30, OV5640_PLL_SYS_ROOT_DIVIDER_BYPASS);
> +	ret = ov5640_mod_reg(sensor, OV5640_REG_SYS_ROOT_DIVIDER, 0x3f,
> +			     (pclk_div << 4) | (sclk2x_div << 2) | sclk_div);
> +	if (ret)
> +		return ret;
> +
> +	return ov5640_write_reg(sensor, OV5640_REG_PCLK_PERIOD, pclk_period);
> +}
> +
> +static u64 ov5640_calc_pixel_rate(struct ov5640_dev *sensor)
> +{
> +	u64 rate;
> +
> +	rate = sensor->current_mode->vtot * sensor->current_mode->htot;
> +	rate *= ov5640_framerates[sensor->current_fr];
> +
> +	return rate;
>  }
>  
>  static unsigned long ov5640_calc_pclk(struct ov5640_dev *sensor,
> @@ -1131,11 +1159,16 @@ static unsigned long ov5640_calc_pclk(struct ov5640_dev *sensor,
>  	return _rate / *pll_rdiv / *bit_div / *pclk_div;
>  }
>  
> -static int ov5640_set_dvp_pclk(struct ov5640_dev *sensor, unsigned long rate)
> +static int ov5640_set_dvp_pclk(struct ov5640_dev *sensor)
>  {
>  	u8 prediv, mult, sysdiv, pll_rdiv, bit_div, pclk_div;
> +	u64 rate;

Do you need a 64-bit integer here, or can the calculation fit in 32-bit?

>  	int ret;
>  
> +	rate = ov5640_calc_pixel_rate(sensor);
> +	rate *= ov5640_code_to_bpp(sensor->fmt.code);
> +	do_div(rate, sensor->ep.bus.parallel.bus_width);
> +
>  	ov5640_calc_pclk(sensor, rate, &prediv, &mult, &sysdiv, &pll_rdiv,
>  			 &bit_div, &pclk_div);
>  
> @@ -1660,16 +1693,6 @@ ov5640_find_mode(struct ov5640_dev *sensor, enum ov5640_frame_rate fr,
>  	return mode;
>  }
>  
> -static u64 ov5640_calc_pixel_rate(struct ov5640_dev *sensor)
> -{
> -	u64 rate;
> -
> -	rate = sensor->current_mode->vtot * sensor->current_mode->htot;
> -	rate *= ov5640_framerates[sensor->current_fr];
> -
> -	return rate;
> -}
> -
>  /*
>   * sensor changes between scaling and subsampling, go through
>   * exposure calculation
> @@ -1851,7 +1874,6 @@ static int ov5640_set_mode(struct ov5640_dev *sensor)
>  	enum ov5640_downsize_mode dn_mode, orig_dn_mode;
>  	bool auto_gain = sensor->ctrls.auto_gain->val == 1;
>  	bool auto_exp =  sensor->ctrls.auto_exp->val == V4L2_EXPOSURE_AUTO;
> -	unsigned long rate;
>  	int ret;
>  
>  	dn_mode = mode->dn_mode;
> @@ -1870,19 +1892,10 @@ static int ov5640_set_mode(struct ov5640_dev *sensor)
>  			goto restore_auto_gain;
>  	}
>  
> -	/*
> -	 * All the formats we support have 16 bits per pixel, seems to require
> -	 * the same rate than YUV, so we can just use 16 bpp all the time.
> -	 */
> -	rate = ov5640_calc_pixel_rate(sensor) * 16;
> -	if (ov5640_is_mipi(sensor)) {
> -		rate = rate / sensor->ep.bus.mipi_csi2.num_data_lanes;
> -		ret = ov5640_set_mipi_pclk(sensor, rate);
> -	} else {
> -		rate = rate / sensor->ep.bus.parallel.bus_width;
> -		ret = ov5640_set_dvp_pclk(sensor, rate);
> -	}
> -
> +	if (ov5640_is_mipi(sensor))
> +		ret = ov5640_set_mipi_pclk(sensor);
> +	else
> +		ret = ov5640_set_dvp_pclk(sensor);
>  	if (ret < 0)
>  		return 0;
>  

-- 
Regards,

Laurent Pinchart

  reply	other threads:[~2022-02-01 17:27 UTC|newest]

Thread overview: 60+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-01-31 14:32 [PATCH 00/17] media: ov5640: Rework the clock tree programming for MIPI Jacopo Mondi
2022-01-31 14:32 ` [PATCH 01/21] media: ov5640: Add pixel rate to modes Jacopo Mondi
2022-02-01 14:52   ` Laurent Pinchart
2022-01-31 14:32 ` [PATCH 02/21] media: ov5604: Re-arrange modes definition Jacopo Mondi
2022-02-01 14:20   ` Laurent Pinchart
2022-01-31 14:32 ` [PATCH 03/21] media: ov5640: Add is_mipi() function Jacopo Mondi
2022-02-01 14:25   ` Laurent Pinchart
2022-01-31 14:32 ` [PATCH 04/21] media: ov5640: Associate bpp with formats Jacopo Mondi
2022-02-01 14:27   ` Laurent Pinchart
2022-01-31 14:32 ` [PATCH 05/21] media: ov5640: Update pixel_rate and link_freq Jacopo Mondi
2022-02-01 16:52   ` Laurent Pinchart
2022-01-31 14:32 ` [PATCH 06/21] media: ov5640: Rework CSI-2 clock tree Jacopo Mondi
2022-02-01 17:27   ` Laurent Pinchart [this message]
2022-02-07 14:07     ` Jacopo Mondi
2022-01-31 14:32 ` [PATCH 07/21] media: ov5640: Rework timings programming Jacopo Mondi
2022-02-01 19:03   ` Laurent Pinchart
2022-02-07 14:37     ` Jacopo Mondi
2022-02-07 16:39       ` Laurent Pinchart
2022-01-31 14:32 ` [PATCH 08/21] media: ov5640: Re-sort per-mode register tables Jacopo Mondi
2022-02-01 19:05   ` Laurent Pinchart
2022-02-07 14:42     ` Jacopo Mondi
2022-01-31 14:32 ` [PATCH 09/21] media: ov5640: Remove ov5640_mode_init_data Jacopo Mondi
2022-02-01 19:07   ` Laurent Pinchart
2022-02-07 14:45     ` Jacopo Mondi
2022-01-31 14:32 ` [PATCH 10/21] media: ov5640: Add HBLANK control Jacopo Mondi
2022-02-02 21:20   ` Laurent Pinchart
2022-01-31 14:32 ` [PATCH 11/21] media: ov5640: Add VBLANK control Jacopo Mondi
2022-02-02 21:35   ` Laurent Pinchart
2022-02-07 15:09     ` Jacopo Mondi
2022-02-07 17:22       ` Laurent Pinchart
2022-02-03  7:58   ` Xavier Roumegue (OSS)
2022-02-07 15:12     ` Jacopo Mondi
2022-01-31 14:44 ` [PATCH 12/21] media: ov5640: Fix durations to comply with FPS Jacopo Mondi
2022-01-31 14:44   ` [PATCH 13/21] media: ov5640: Initialize try format Jacopo Mondi
2022-02-02 21:51     ` Laurent Pinchart
2022-01-31 14:44   ` [PATCH 14/21] media: ov5640: Implement get_selection Jacopo Mondi
2022-02-02 22:29     ` Laurent Pinchart
2022-02-07 15:47       ` Jacopo Mondi
2022-02-07 17:53         ` Laurent Pinchart
2022-02-08 14:18           ` Jacopo Mondi
2022-02-08 14:41             ` Laurent Pinchart
2022-01-31 14:44   ` [PATCH 15/21] media: ov5640: Limit format to FPS in DVP mode only Jacopo Mondi
2022-02-02 22:38     ` Laurent Pinchart
2022-02-07 15:49       ` Jacopo Mondi
2022-01-31 14:44   ` [PATCH 16/21] media: ov5640: Disable s_frame_interval in MIPI mode Jacopo Mondi
2022-02-02 22:40     ` Laurent Pinchart
2022-02-02 21:48   ` [PATCH 12/21] media: ov5640: Fix durations to comply with FPS Laurent Pinchart
2022-02-07 15:58     ` Jacopo Mondi
2022-01-31 14:45 ` [PATCH 17/21] media: ov5640: Register device properties Jacopo Mondi
2022-01-31 14:45   ` [PATCH 18/21] media: ov5640: Add RGB565_1X16 format Jacopo Mondi
2022-02-02 22:48     ` Laurent Pinchart
2022-01-31 14:45   ` [PATCH 19/21] media: ov5640: Add RGB888/BGR888 formats Jacopo Mondi
2022-02-02 22:49     ` Laurent Pinchart
2022-02-02 22:44   ` [PATCH 17/21] media: ov5640: Register device properties Laurent Pinchart
2022-01-31 14:45 ` [PATCH 20/21] media: ov5640: Restrict sizes to mbus code Jacopo Mondi
2022-01-31 14:45   ` [PATCH 21/21] media: ov5640: Adjust format to bpp in s_fmt Jacopo Mondi
2022-02-02 23:03     ` Laurent Pinchart
2022-02-07 16:07       ` Jacopo Mondi
2022-02-07 16:46         ` Laurent Pinchart
2022-02-02 22:57   ` [PATCH 20/21] media: ov5640: Restrict sizes to mbus code Laurent Pinchart

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=YfltgzUdzbQjmLyt@pendragon.ideasonboard.com \
    --to=laurent.pinchart@ideasonboard.com \
    --cc=Eugen.Hristev@microchip.com \
    --cc=aford173@gmail.com \
    --cc=festevam@gmail.com \
    --cc=hugues.fruchet@st.com \
    --cc=hverkuil-cisco@xs4all.nl \
    --cc=jacopo@jmondi.org \
    --cc=jbrunet@baylibre.com \
    --cc=linux-media@vger.kernel.org \
    --cc=mchehab@kernel.org \
    --cc=mirela.rabulea@nxp.com \
    --cc=prabhakar.mahadev-lad.rj@bp.renesas.com \
    --cc=sakari.ailus@iki.fi \
    --cc=slongerbeam@gmail.com \
    --cc=tomi.valkeinen@ideasonboard.com \
    --cc=xavier.roumegue@oss.nxp.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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.