Re: [PATCH 08/12] media: ov5640: Adjust the clock based on the expected rate

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi Sakari,

On Fri, Mar 09, 2018 at 01:16:24PM +0200, Sakari Ailus wrote:
> > + *
> > + *   +--------------+
> > + *   |  Oscillator  |
> 
> I wonder if this should be simply called external clock, that's what the
> sensor uses.

Ack

> > + *   +------+-------+
> > + *          |
> > + *   +------+-------+
> > + *   | System clock | - reg 0x3035, bits 4-7
> > + *   +------+-------+
> > + *          |
> > + *   +------+-------+ - reg 0x3036, for the multiplier
> > + *   |     PLL      | - reg 0x3037, bits 4 for the root divider
> > + *   +------+-------+ - reg 0x3037, bits 0-3 for the pre-divider
> > + *          |
> > + *   +------+-------+
> > + *   |     SCLK     | - reg 0x3108, bits 0-1 for the root divider
> > + *   +------+-------+
> > + *          |
> > + *   +------+-------+
> > + *   |    PCLK      | - reg 0x3108, bits 4-5 for the root divider
> > + *   +--------------+
> > + *
> > + * This is deviating from the datasheet at least for the register
> > + * 0x3108, since it's said here that the PCLK would be clocked from
> > + * the PLL. However, changing the SCLK divider value has a direct
> > + * effect on the PCLK rate, which wouldn't be the case if both PCLK
> > + * and SCLK were to be sourced from the PLL.
> > + *
> > + * These parameters also match perfectly the rate that is output by
> > + * the sensor, so we shouldn't have too much factors missing (or they
> > + * would be set to 1).
> > + */
> > +
> > +/*
> > + * FIXME: This is supposed to be ranging from 1 to 16, but the value
> > + * is always set to either 1 or 2 in the vendor kernels.
> 
> There could be limits for the clock rates after the first divider. In
> practice the clock rates are mostly one of the common frequencies (9,6; 12;
> 19,2 or 24 MHz) so there's no need to use the other values.

There's probably some limits on the various combinations as well. I
first tried to use the full range, and there was some combinations
that were not usable, even though the clock rate should have been
correct.

> > + */
> > +#define OV5640_SYSDIV_MIN	1
> > +#define OV5640_SYSDIV_MAX	2
> > +
> > +static unsigned long ov5640_calc_sysclk(struct ov5640_dev *sensor,
> > +					unsigned long rate,
> > +					u8 *sysdiv)
> > +{
> > +	unsigned long best = ~0;
> > +	u8 best_sysdiv = 1;
> > +	u8 _sysdiv;
> > +
> > +	for (_sysdiv = OV5640_SYSDIV_MIN;
> > +	     _sysdiv <= OV5640_SYSDIV_MAX;
> > +	     _sysdiv++) {
> > +		unsigned long tmp;
> > +
> > +		tmp = sensor->xclk_freq / _sysdiv;
> > +		if (abs(rate - tmp) < abs(rate - best)) {
> > +			best = tmp;
> > +			best_sysdiv = _sysdiv;
> > +		}
> > +
> > +		if (tmp == rate)
> > +			goto out;
> > +	}
> > +
> > +out:
> > +	*sysdiv = best_sysdiv;
> > +	return best;
> > +}
> > +
> > +/*
> > + * FIXME: This is supposed to be ranging from 1 to 8, but the value is
> > + * always set to 3 in the vendor kernels.
> > + */
> > +#define OV5640_PLL_PREDIV_MIN	3
> > +#define OV5640_PLL_PREDIV_MAX	3
> 
> Same reasoning here than above. I might leave a comment documenting the
> values the hardware supports, removing FIXME as this isn't really an issue
> as far as I see.

Ok, I'll do it then

> > +
> > +/*
> > + * FIXME: This is supposed to be ranging from 1 to 2, but the value is
> > + * always set to 1 in the vendor kernels.
> > + */
> > +#define OV5640_PLL_ROOT_DIV_MIN	1
> > +#define OV5640_PLL_ROOT_DIV_MAX	1
> > +
> > +#define OV5640_PLL_MULT_MIN	4
> > +#define OV5640_PLL_MULT_MAX	252
> > +
> > +static unsigned long ov5640_calc_pll(struct ov5640_dev *sensor,
> > +				     unsigned long rate,
> > +				     u8 *sysdiv, u8 *prediv, u8 *rdiv, u8 *mult)
> > +{
> > +	unsigned long best = ~0;
> > +	u8 best_sysdiv = 1, best_prediv = 1, best_mult = 1, best_rdiv = 1;
> > +	u8 _prediv, _mult, _rdiv;
> > +
> > +	for (_prediv = OV5640_PLL_PREDIV_MIN;
> > +	     _prediv <= OV5640_PLL_PREDIV_MAX;
> > +	     _prediv++) {
> > +		for (_mult = OV5640_PLL_MULT_MIN;
> > +		     _mult <= OV5640_PLL_MULT_MAX;
> > +		     _mult++) {
> > +			for (_rdiv = OV5640_PLL_ROOT_DIV_MIN;
> > +			     _rdiv <= OV5640_PLL_ROOT_DIV_MAX;
> > +			     _rdiv++) {
> > +				unsigned long pll;
> > +				unsigned long sysclk;
> > +				u8 _sysdiv;
> > +
> > +				/*
> > +				 * The PLL multiplier cannot be odd if
> > +				 * above 127.
> > +				 */
> > +				if (_mult > 127 && !(_mult % 2))
> > +					continue;
> > +
> > +				sysclk = rate * _prediv * _rdiv / _mult;
> > +				sysclk = ov5640_calc_sysclk(sensor, sysclk,
> > +							    &_sysdiv);
> > +
> > +				pll = sysclk / _rdiv / _prediv * _mult;
> > +				if (abs(rate - pll) < abs(rate - best)) {
> > +					best = pll;
> > +					best_sysdiv = _sysdiv;
> > +					best_prediv = _prediv;
> > +					best_mult = _mult;
> > +					best_rdiv = _rdiv;
> 
> The smiapp PLL calculator only accepts an exact match. That hasn't been an
> issue previously, I wonder if this would work here, too.

I don't recall which one exactly, but I think at least 480p@30fps
wasn't an exact match in our case. Given the insanely high blanking
periods, we might reduce them in order to fall back to something
exact, but I really wanted to be as close to what was already done in
the bytes array as possible, given the already quite intrusive nature
of the patches.

> I think you could remove the inner loop, too, if put what
> ov5640_calc_sysclk() does here. You know the desired clock rate so you can
> calculate the total divisor (_rdiv * sysclk divider).

I guess we can have two approaches here. Since most of the dividers
are fixed, I could have a much simpler code anyway, or I could keep it
that way if we ever want to extend it.

It seems you imply that you'd like something simpler, so I can even
simplify much more than what's already there if you want.

Maxime

-- 
Maxime Ripard, Bootlin (formerly Free Electrons)
Embedded Linux and Kernel engineering
https://bootlin.com

Attachment: signature.asc
Description: PGP signature


[Index of Archives]     [Linux Input]     [Video for Linux]     [Gstreamer Embedded]     [Mplayer Users]     [Linux USB Devel]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [Yosemite Backpacking]
  Powered by Linux