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

2018-03-15 Thread Sakari Ailus
On Tue, Mar 13, 2018 at 01:49:37PM +0100, Maxime Ripard wrote:
> 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.

Apart from the multipliers and dividers, each node in the clock tree likely
has minimum and maximum frequencies. One way to try to figure out those
limits is to figure out which frequencies are used in existing mode
definitions. Sensor documentation seldom contains that information.

> 
> > > + */
> > > +#define OV5640_SYSDIV_MIN1
> > > +#define OV5640_SYSDIV_MAX2
> > > +
> > > +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_MIN3
> > > +#define OV5640_PLL_PREDIV_MAX3
> > 
> > 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 

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

2018-03-13 Thread Maxime Ripard
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_MIN1
> > +#define OV5640_PLL_ROOT_DIV_MAX1
> > +
> > +#define OV5640_PLL_MULT_MIN4
> > +#define OV5640_PLL_MULT_MAX252
> > +
> > +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 = 

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

2018-03-09 Thread Sakari Ailus
Hi Maxime,

On Fri, Mar 02, 2018 at 03:34:56PM +0100, Maxime Ripard wrote:
...
> @@ -902,6 +920,246 @@ static int ov5640_mod_reg(struct ov5640_dev *sensor, 
> u16 reg,
>   return ov5640_write_reg(sensor, reg, val);
>  }
>  
> +/*
> + * After spending way too much time trying the various combinations, I
> + * believe the clock tree is as follows:

Wow! I've never heard of anyone doing this on non-SMIA compliant sensors.

> + *
> + *   +--+
> + *   |  Oscillator  |

I wonder if this should be simply called external clock, that's what the
sensor uses.

> + *   +--+---+
> + *  |
> + *   +--+---+
> + *   | 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.

> + */
> +#define OV5640_SYSDIV_MIN1
> +#define OV5640_SYSDIV_MAX2
> +
> +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_MIN3
> +#define OV5640_PLL_PREDIV_MAX3


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.

> +
> +/*
> + * 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,
> +   

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

2018-03-02 Thread Maxime Ripard
The clock structure for the PCLK is quite obscure in the documentation, and
was hardcoded through the bytes array of each and every mode.

This is troublesome, since we cannot adjust it at runtime based on other
parameters (such as the number of bytes per pixel), and we can't support
either framerates that have not been used by the various vendors, since we
don't have the needed initialization sequence.

We can however understand how the clock tree works, and then implement some
functions to derive the various parameters from a given rate. And now that
those parameters are calculated at runtime, we can remove them from the
initialization sequence.

The modes also gained a new parameter which is the clock that they are
running at, from the register writes they were doing, so for now the switch
to the new algorithm should be transparent.

Signed-off-by: Maxime Ripard 
---
 drivers/media/i2c/ov5640.c | 316 +
 1 file changed, 291 insertions(+), 25 deletions(-)

diff --git a/drivers/media/i2c/ov5640.c b/drivers/media/i2c/ov5640.c
index 0eeb1667bbe7..323cde27dd8b 100644
--- a/drivers/media/i2c/ov5640.c
+++ b/drivers/media/i2c/ov5640.c
@@ -172,6 +172,7 @@ struct ov5640_mode_info {
u32 htot;
u32 vact;
u32 vtot;
+   u32 clock;
const struct reg_value *reg_data;
u32 reg_data_size;
 };
@@ -255,8 +256,8 @@ static const struct reg_value 
ov5640_init_setting_30fps_VGA[] = {
 
{0x3103, 0x11, 0, 0}, {0x3008, 0x82, 0, 5}, {0x3008, 0x42, 0, 0},
{0x3103, 0x03, 0, 0}, {0x3017, 0x00, 0, 0}, {0x3018, 0x00, 0, 0},
-   {0x3034, 0x18, 0, 0}, {0x3035, 0x14, 0, 0}, {0x3036, 0x38, 0, 0},
-   {0x3037, 0x13, 0, 0}, {0x3630, 0x36, 0, 0},
+   {0x3034, 0x18, 0, 0},
+   {0x3630, 0x36, 0, 0},
{0x3631, 0x0e, 0, 0}, {0x3632, 0xe2, 0, 0}, {0x3633, 0x12, 0, 0},
{0x3621, 0xe0, 0, 0}, {0x3704, 0xa0, 0, 0}, {0x3703, 0x5a, 0, 0},
{0x3715, 0x78, 0, 0}, {0x3717, 0x01, 0, 0}, {0x370b, 0x60, 0, 0},
@@ -340,7 +341,7 @@ static const struct reg_value 
ov5640_init_setting_30fps_VGA[] = {
 
 static const struct reg_value ov5640_setting_30fps_VGA_640_480[] = {
 
-   {0x3035, 0x14, 0, 0}, {0x3036, 0x38, 0, 0}, {0x3c07, 0x08, 0, 0},
+   {0x3c07, 0x08, 0, 0},
{0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
{0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, {0x3814, 0x31, 0, 0},
{0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0},
@@ -359,7 +360,7 @@ static const struct reg_value 
ov5640_setting_30fps_VGA_640_480[] = {
 };
 
 static const struct reg_value ov5640_setting_15fps_VGA_640_480[] = {
-   {0x3035, 0x22, 0, 0}, {0x3036, 0x38, 0, 0}, {0x3c07, 0x08, 0, 0},
+   {0x3c07, 0x08, 0, 0},
{0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
{0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, {0x3814, 0x31, 0, 0},
{0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0},
@@ -379,7 +380,7 @@ static const struct reg_value 
ov5640_setting_15fps_VGA_640_480[] = {
 
 static const struct reg_value ov5640_setting_30fps_XGA_1024_768[] = {
 
-   {0x3035, 0x14, 0, 0}, {0x3036, 0x38, 0, 0}, {0x3c07, 0x08, 0, 0},
+   {0x3c07, 0x08, 0, 0},
{0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
{0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, {0x3814, 0x31, 0, 0},
{0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0},
@@ -395,11 +396,10 @@ static const struct reg_value 
ov5640_setting_30fps_XGA_1024_768[] = {
{0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x4713, 0x03, 0, 0},
{0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0},
{0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0}, {0x3503, 0x00, 0, 0},
-   {0x3035, 0x12, 0, 0},
 };
 
 static const struct reg_value ov5640_setting_15fps_XGA_1024_768[] = {
-   {0x3035, 0x22, 0, 0}, {0x3036, 0x38, 0, 0}, {0x3c07, 0x08, 0, 0},
+   {0x3c07, 0x08, 0, 0},
{0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
{0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, {0x3814, 0x31, 0, 0},
{0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0},
@@ -418,7 +418,7 @@ static const struct reg_value 
ov5640_setting_15fps_XGA_1024_768[] = {
 };
 
 static const struct reg_value ov5640_setting_30fps_QVGA_320_240[] = {
-   {0x3035, 0x14, 0, 0}, {0x3036, 0x38, 0, 0}, {0x3c07, 0x08, 0, 0},
+   {0x3c07, 0x08, 0, 0},
{0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
{0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, {0x3814, 0x31, 0, 0},
{0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0},
@@ -437,7 +437,7 @@ static const struct reg_value 
ov5640_setting_30fps_QVGA_320_240[] = {
 };
 
 static const struct reg_value ov5640_setting_15fps_QVGA_320_240[] = {
-   {0x3035, 0x22, 0, 0}, {0x3036, 0x38, 0, 0}, {0x3c07,