Skip to contentSkip to conversation

sun9i pll4 upstream kernel code seems wrong

DISCUSSION Hans de Goede 2 participants 7 messages Jan 17, 2015 – Jan 20, 2015

lore
Share & tools
lore
#0 lore raw

Hi ChenYu,

Looking at drivers/clk/sunxi/clk-sun9i-core.c:

sun9i_a80_get_pll4_factors(), and comparing it with the A80 user manual, things seem way off, this seems more accurate (although also possibly not quite) for pll1 / pll2 then for pll4, and the comment at the top does mention PLL1 once.

Note according to the datasheet pll4 should be treated as an inmutable pll fixed at 960 MHz, so maybe we should just drop the get_factors function for it ?

Luckily the struct clk_factors_config sun9i_a80_pll4_config is correct, so as long as we do not try to change the rate the current upstream code for pll4 does work.

Regards,

Hans

#1 lore raw

Hi,

Quoted 9 lines · Hans de Goede

Hi ChenYu,

Looking at drivers/clk/sunxi/clk-sun9i-core.c:

sun9i_a80_get_pll4_factors(), and comparing it with the A80 user manual, things seem way off, this seems more accurate (although also possibly not quite) for pll1 / pll2 then for pll4, and the comment at the top does mention PLL1 once.

PLL1 was mentioned as I forgot to change that one in the comment. I copied the comment section from others.

Other than that, I'm not sure what part is off. The code was done without the user manual, only with the SDK bits. I think in the SDK the minimum value of 12 for N factor was not mentioned. But other than that, it should work fine.

Note the "div" variable uses a base frequency of 6, not 24. I used a spreadsheet to do some calculations to see if the code does output the right numbers. Unfortunately I don't have either the notes or the spreadsheet I used back then. It would take me a bit of time to check.

Quoted 3 lines

Note according to the datasheet pll4 should be treated as an inmutable pll fixed at 960 MHz, so maybe we should just drop the get_factors function for it ?

Is that acceptable? Or is there a readonly flag we should set for the clock?

Regards,
ChenYu

Quoted 7 lines

Luckily the struct clk_factors_config sun9i_a80_pll4_config is correct, so as long as we do not try to change the rate the current upstream code for pll4 does work.

Regards,

Hans

#2 lore raw

Hi,

Quoted 13 lines · Chen-Yu Tsai

Hi,

Quoted 9 lines · Hans de Goede

Hi ChenYu,

Looking at drivers/clk/sunxi/clk-sun9i-core.c:

sun9i_a80_get_pll4_factors(), and comparing it with the A80 user manual, things seem way off, this seems more accurate (although also possibly not quite) for pll1 / pll2 then for pll4, and the comment at the top does mention PLL1 once.

Quoted 8 lines

PLL1 was mentioned as I forgot to change that one in the comment. I copied the comment section from others.

Other than that, I'm not sure what part is off. The code was done without the user manual, only with the SDK bits. I think in the SDK the minimum value of 12 for N factor was not mentioned. But other than that, it should work fine.

Ok, so looking at the code again it is not that much of, just hard to read, and it does contain some errors:

         /* divs above 256 cannot be odd */
         if (div > 256)
                 div = round_up(div, 2);

Should be:

         /* divs above 255 must be a multiple of 2 */
         if (div > 255)
                 div = round_up(div, 2);

Note the 255, and replacing must be odd with a multiple of 2, as this had nothing to do with odd / even (more on that later).

Likewise this:

	/* divs above 512 must be a multiple of 4 */
         if (div > 512)
                 div = round_up(div, 4);

Should have s/512/511/ done on it.

And this:

         /* m will be 1 if div is odd */
         if (div & 1)
                 *m = 1;
         else
                 *m = 0;

Is nonsense, the div may have been odd all along, (never been rounded) and we should still use m = 1, e.g. to make 78 MHz.

So this should be:

         if (div < 256)
                 *m = 1;
         else
                 *m = 0;

Preferably I would like to see the entire thing rewritten into something IMHO much more readable / less error prone, like this:

{
	u8 n;
	u8 m = 1;
	u8 p = 1;

	/* Normalize value to a 6M multiple */
	n = DIV_ROUND_UP(*freq, 6000000);

	if (n > 255) {
		m = 0;
		n = (n + 1) / 2;
	}
		
	if (n > 255) {
		p = 0;
		n = (n + 1) / 2;
	}

	if (n > 255)
		n = 255;
	else if (n < 12)
		n = 12;

	*freq = ((24000000 * n) >> p) / (m + 1);

	if (n_ret == NULL)
		return;

	*n_ret = n;
	*m_ret = m;
	*p_ret = p;
}

With the n / m / p function parameters renamed to foo_ret.

Regards,

Hans

Quoted 25 lines

Note the "div" variable uses a base frequency of 6, not 24. I used a spreadsheet to do some calculations to see if the code does output the right numbers. Unfortunately I don't have either the notes or the spreadsheet I used back then. It would take me a bit of time to check.

Quoted 3 lines

Note according to the datasheet pll4 should be treated as an inmutable pll fixed at 960 MHz, so maybe we should just drop the get_factors function for it ?

Is that acceptable? Or is there a readonly flag we should set for the clock?

Regards,
ChenYu

Quoted 7 lines

Luckily the struct clk_factors_config sun9i_a80_pll4_config is correct, so as long as we do not try to change the rate the current upstream code for pll4 does work.

Regards,

Hans

#3 lore raw

Hi,

Quoted 58 lines · Hans de Goede

Hi,

Quoted 13 lines · Chen-Yu Tsai

Hi,

Quoted 9 lines · Hans de Goede

Hi ChenYu,

Looking at drivers/clk/sunxi/clk-sun9i-core.c:

sun9i_a80_get_pll4_factors(), and comparing it with the A80 user manual, things seem way off, this seems more accurate (although also possibly not quite) for pll1 / pll2 then for pll4, and the comment at the top does mention PLL1 once.

Quoted 8 lines

PLL1 was mentioned as I forgot to change that one in the comment. I copied the comment section from others.

Other than that, I'm not sure what part is off. The code was done without the user manual, only with the SDK bits. I think in the SDK the minimum value of 12 for N factor was not mentioned. But other than that, it should work fine.

Ok, so looking at the code again it is not that much of, just hard to read, and it does contain some errors:

         /* divs above 256 cannot be odd */
         if (div > 256)
                 div = round_up(div, 2);

Should be:

         /* divs above 255 must be a multiple of 2 */
         if (div > 255)
                 div = round_up(div, 2);

Note the 255, and replacing must be odd with a multiple of 2, as this had nothing to do with odd / even (more on that later).

Likewise this:

     /* divs above 512 must be a multiple of 4 */
         if (div > 512)
                 div = round_up(div, 4);

Should have s/512/511/ done on it.

And this:

         /* m will be 1 if div is odd */
         if (div & 1)
                 *m = 1;
         else
                 *m = 0;
Quoted 3 lines

Is nonsense, the div may have been odd all along, (never been rounded) and we should still use m = 1, e.g. to make 78 MHz.

Correction this should read:

Is nonsense, the div may have been *even* all along, (never been rounded) and we should still use m = 1, e.g. to make *72* MHz.

Regards,

Hans

Quoted 77 lines

So this should be:

         if (div < 256)
                 *m = 1;
         else
                 *m = 0;

Preferably I would like to see the entire thing rewritten into something IMHO much more readable / less error prone, like this:

{
     u8 n;
     u8 m = 1;
     u8 p = 1;

     /* Normalize value to a 6M multiple */
     n = DIV_ROUND_UP(*freq, 6000000);

     if (n > 255) {
         m = 0;
         n = (n + 1) / 2;
     }

     if (n > 255) {
         p = 0;
         n = (n + 1) / 2;
     }

     if (n > 255)
         n = 255;
     else if (n < 12)
         n = 12;

     *freq = ((24000000 * n) >> p) / (m + 1);

     if (n_ret == NULL)
         return;

     *n_ret = n;
     *m_ret = m;
     *p_ret = p;
}

With the n / m / p function parameters renamed to foo_ret.

Regards,

Hans

Quoted 25 lines

Note the "div" variable uses a base frequency of 6, not 24. I used a spreadsheet to do some calculations to see if the code does output the right numbers. Unfortunately I don't have either the notes or the spreadsheet I used back then. It would take me a bit of time to check.

Quoted 3 lines

Note according to the datasheet pll4 should be treated as an inmutable pll fixed at 960 MHz, so maybe we should just drop the get_factors function for it ?

Is that acceptable? Or is there a readonly flag we should set for the clock?

Regards,
ChenYu

Quoted 7 lines

Luckily the struct clk_factors_config sun9i_a80_pll4_config is correct, so as long as we do not try to change the rate the current upstream code for pll4 does work.

Regards,

Hans

#4 lore raw

Hi,

Quoted 73 lines · Hans de Goede

Hi,

Quoted 64 lines · Hans de Goede

Hi,

Quoted 17 lines · Chen-Yu Tsai

Hi,

Quoted 10 lines · Hans de Goede

Hi ChenYu,

Looking at drivers/clk/sunxi/clk-sun9i-core.c:

sun9i_a80_get_pll4_factors(), and comparing it with the A80 user manual, things seem way off, this seems more accurate (although also possibly not quite) for pll1 / pll2 then for pll4, and the comment at the top does mention PLL1 once.

Quoted 8 lines

PLL1 was mentioned as I forgot to change that one in the comment. I copied the comment section from others.

Other than that, I'm not sure what part is off. The code was done without the user manual, only with the SDK bits. I think in the SDK the minimum value of 12 for N factor was not mentioned. But other than that, it should work fine.

Ok, so looking at the code again it is not that much of, just hard to read, and it does contain some errors:

         /* divs above 256 cannot be odd */
         if (div > 256)
                 div = round_up(div, 2);

Should be:

         /* divs above 255 must be a multiple of 2 */
         if (div > 255)
                 div = round_up(div, 2);

Note the 255, and replacing must be odd with a multiple of 2, as this had nothing to do with odd / even (more on that later).

Likewise this:

     /* divs above 512 must be a multiple of 4 */
         if (div > 512)
                 div = round_up(div, 4);

Should have s/512/511/ done on it.

And this:

         /* m will be 1 if div is odd */
         if (div & 1)
                 *m = 1;
         else
                 *m = 0;
Quoted 3 lines

Is nonsense, the div may have been odd all along, (never been rounded) and we should still use m = 1, e.g. to make 78 MHz.

Quoted 5 lines

Correction this should read:

Is nonsense, the div may have been *even* all along, (never been rounded) and we should still use m = 1, e.g. to make *72* MHz.

The m and p constraints were based on comments in the original SDK code, which weren't very clear as to if they were hardware constraints or just preferred behavior in the code path. Looking back, I agree the work done by me here could have been better.

Quoted 51 lines

Regards,

Hans

Quoted 46 lines

So this should be:

         if (div < 256)
                 *m = 1;
         else
                 *m = 0;

Preferably I would like to see the entire thing rewritten into something IMHO much more readable / less error prone, like this:

{
     u8 n;
     u8 m = 1;
     u8 p = 1;

     /* Normalize value to a 6M multiple */
     n = DIV_ROUND_UP(*freq, 6000000);

     if (n > 255) {
         m = 0;
         n = (n + 1) / 2;
     }

     if (n > 255) {
         p = 0;
         n = (n + 1) / 2;
     }

     if (n > 255)
         n = 255;
     else if (n < 12)
         n = 12;

     *freq = ((24000000 * n) >> p) / (m + 1);

     if (n_ret == NULL)
         return;

     *n_ret = n;
     *m_ret = m;
     *p_ret = p;
}

With the n / m / p function parameters renamed to foo_ret.

Since you've pretty much wrote the whole function, would you send a patch out when you get the chance?

Thanks
ChenYu

Quoted 31 lines
Quoted 31 lines

Regards,

Hans

Quoted 26 lines

Note the "div" variable uses a base frequency of 6, not 24. I used a spreadsheet to do some calculations to see if the code does output the right numbers. Unfortunately I don't have either the notes or the spreadsheet I used back then. It would take me a bit of time to check.

Quoted 3 lines

Note according to the datasheet pll4 should be treated as an inmutable pll fixed at 960 MHz, so maybe we should just drop the get_factors function for it ?

Is that acceptable? Or is there a readonly flag we should set for the clock?

Regards,
ChenYu

Quoted 7 lines

Luckily the struct clk_factors_config sun9i_a80_pll4_config is correct, so as long as we do not try to change the rate the current upstream code for pll4 does work.

Regards,

Hans

#5 lore raw

Hi,

Quoted 138 lines · Chen-Yu Tsai

Hi,

Quoted 73 lines · Hans de Goede

Hi,

Quoted 64 lines · Hans de Goede

Hi,

Quoted 17 lines · Chen-Yu Tsai

Hi,

Quoted 10 lines · Hans de Goede

Hi ChenYu,

Looking at drivers/clk/sunxi/clk-sun9i-core.c:

sun9i_a80_get_pll4_factors(), and comparing it with the A80 user manual, things seem way off, this seems more accurate (although also possibly not quite) for pll1 / pll2 then for pll4, and the comment at the top does mention PLL1 once.

Quoted 8 lines

PLL1 was mentioned as I forgot to change that one in the comment. I copied the comment section from others.

Other than that, I'm not sure what part is off. The code was done without the user manual, only with the SDK bits. I think in the SDK the minimum value of 12 for N factor was not mentioned. But other than that, it should work fine.

Ok, so looking at the code again it is not that much of, just hard to read, and it does contain some errors:

          /* divs above 256 cannot be odd */
          if (div > 256)
                  div = round_up(div, 2);

Should be:

          /* divs above 255 must be a multiple of 2 */
          if (div > 255)
                  div = round_up(div, 2);

Note the 255, and replacing must be odd with a multiple of 2, as this had nothing to do with odd / even (more on that later).

Likewise this:

      /* divs above 512 must be a multiple of 4 */
          if (div > 512)
                  div = round_up(div, 4);

Should have s/512/511/ done on it.

And this:

          /* m will be 1 if div is odd */
          if (div & 1)
                  *m = 1;
          else
                  *m = 0;
Quoted 3 lines

Is nonsense, the div may have been odd all along, (never been rounded) and we should still use m = 1, e.g. to make 78 MHz.

Quoted 5 lines

Correction this should read:

Is nonsense, the div may have been *even* all along, (never been rounded) and we should still use m = 1, e.g. to make *72* MHz.

The m and p constraints were based on comments in the original SDK code, which weren't very clear as to if they were hardware constraints or just preferred behavior in the code path. Looking back, I agree the work done by me here could have been better.

Quoted 50 lines

Regards,

Hans

Quoted 45 lines

So this should be:

          if (div < 256)
                  *m = 1;
          else
                  *m = 0;

Preferably I would like to see the entire thing rewritten into something IMHO much more readable / less error prone, like this:

{
      u8 n;
      u8 m = 1;
      u8 p = 1;

      /* Normalize value to a 6M multiple */
      n = DIV_ROUND_UP(*freq, 6000000);

      if (n > 255) {
          m = 0;
          n = (n + 1) / 2;
      }

      if (n > 255) {
          p = 0;
          n = (n + 1) / 2;
      }

      if (n > 255)
          n = 255;
      else if (n < 12)
          n = 12;

      *freq = ((24000000 * n) >> p) / (m + 1);

      if (n_ret == NULL)
          return;

      *n_ret = n;
      *m_ret = m;
      *p_ret = p;
}
Quoted 4 lines
Quoted 1 line
Quoted 1 line

With the n / m / p function parameters renamed to foo_ret.

Since you've pretty much wrote the whole function, would you send a patch out when you get the chance?

Sure, the reason I was proposing this by mail first was to see if you agree that something like the above will be better, if you agree I'll turn this into a patch.

Regards,

Hans

#6 lore raw
Quoted 155 lines · Hans de Goede

Hi,

Quoted 151 lines · Chen-Yu Tsai

Hi,

Quoted 80 lines · Hans de Goede

Hi,

Quoted 69 lines · Hans de Goede

Hi,

Quoted 20 lines · Chen-Yu Tsai

Hi,

Quoted 11 lines · Hans de Goede

Hi ChenYu,

Looking at drivers/clk/sunxi/clk-sun9i-core.c:

sun9i_a80_get_pll4_factors(), and comparing it with the A80 user manual, things seem way off, this seems more accurate (although also possibly not quite) for pll1 / pll2 then for pll4, and the comment at the top does mention PLL1 once.

Quoted 8 lines

PLL1 was mentioned as I forgot to change that one in the comment. I copied the comment section from others.

Other than that, I'm not sure what part is off. The code was done without the user manual, only with the SDK bits. I think in the SDK the minimum value of 12 for N factor was not mentioned. But other than that, it should work fine.

Ok, so looking at the code again it is not that much of, just hard to read, and it does contain some errors:

          /* divs above 256 cannot be odd */
          if (div > 256)
                  div = round_up(div, 2);

Should be:

          /* divs above 255 must be a multiple of 2 */
          if (div > 255)
                  div = round_up(div, 2);

Note the 255, and replacing must be odd with a multiple of 2, as this had nothing to do with odd / even (more on that later).

Likewise this:

      /* divs above 512 must be a multiple of 4 */
          if (div > 512)
                  div = round_up(div, 4);

Should have s/512/511/ done on it.

And this:

          /* m will be 1 if div is odd */
          if (div & 1)
                  *m = 1;
          else
                  *m = 0;
Quoted 3 lines

Is nonsense, the div may have been odd all along, (never been rounded) and we should still use m = 1, e.g. to make 78 MHz.

Quoted 5 lines

Correction this should read:

Is nonsense, the div may have been *even* all along, (never been rounded) and we should still use m = 1, e.g. to make *72* MHz.

The m and p constraints were based on comments in the original SDK code, which weren't very clear as to if they were hardware constraints or just preferred behavior in the code path. Looking back, I agree the work done by me here could have been better.

Quoted 51 lines

Regards,

Hans

Quoted 46 lines

So this should be:

          if (div < 256)
                  *m = 1;
          else
                  *m = 0;

Preferably I would like to see the entire thing rewritten into something IMHO much more readable / less error prone, like this:

{
      u8 n;
      u8 m = 1;
      u8 p = 1;

      /* Normalize value to a 6M multiple */
      n = DIV_ROUND_UP(*freq, 6000000);

      if (n > 255) {
          m = 0;
          n = (n + 1) / 2;
      }

      if (n > 255) {
          p = 0;
          n = (n + 1) / 2;
      }

      if (n > 255)
          n = 255;
      else if (n < 12)
          n = 12;

      *freq = ((24000000 * n) >> p) / (m + 1);

      if (n_ret == NULL)
          return;

      *n_ret = n;
      *m_ret = m;
      *p_ret = p;
}

With the n / m / p function parameters renamed to foo_ret.

Quoted 7 lines
Quoted 2 lines

Since you've pretty much wrote the whole function, would you send a patch out when you get the chance?

Sure, the reason I was proposing this by mail first was to see if you agree that something like the above will be better, if you agree I'll turn this into a patch.

I say go for it. I'm a bit busy with travel preparations and other stuff this week, so I haven't tested the sample above.

ChenYu