summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristoph Muellner <christoph.muellner@theobroma-systems.com>2015-05-05 22:50:26 +0200
committerKlaus Goger <klaus.goger@theobroma-systems.com>2015-07-30 18:52:57 +0200
commitdb74f63aa29c867c76e5578674355d3ef6b82a96 (patch)
tree89e5d8d49b1c99c74f9730ab07a4ab04b0379f4f
parent7ce3d59bcfbf650de4116a2bdf83c69de2267e0a (diff)
Clk: sunxi: Fixing sun6i PLL1 factor calculation.
The previous implementation was errornous and hard to debug. This patch provides a much simpler algorithm, which has been successfully tested on an Allwinner A31 based board. Signed-off-by: Christoph Muellner <christoph.muellner@theobroma-systems.com>
-rw-r--r--drivers/clk/sunxi/clk-sunxi.c97
1 files changed, 33 insertions, 64 deletions
diff --git a/drivers/clk/sunxi/clk-sunxi.c b/drivers/clk/sunxi/clk-sunxi.c
index 783acb5bb78a..9c0dc7438774 100644
--- a/drivers/clk/sunxi/clk-sunxi.c
+++ b/drivers/clk/sunxi/clk-sunxi.c
@@ -299,78 +299,47 @@ static void sun4i_get_pll1_factors(u32 *freq, u32 parent_rate,
static void sun6i_a31_get_pll1_factors(u32 *freq, u32 parent_rate,
u8 *n, u8 *k, u8 *m, u8 *p)
{
- /*
- * We can operate only on MHz, this will make our life easier
- * later.
- */
- u32 freq_mhz = *freq / 1000000;
- u32 parent_freq_mhz = parent_rate / 1000000;
-
- /*
- * Round down the frequency to the closest multiple of either
- * 6 or 16
- */
- u32 round_freq_6 = round_down(freq_mhz, 6);
- u32 round_freq_16 = round_down(freq_mhz, 16);
-
- if (round_freq_6 > round_freq_16)
- freq_mhz = round_freq_6;
+ const u32 parent_mhz = 24;
+ const u8 N_max = 32; /* 5 bits */
+ const u8 K_max = 4; /* 2 bits */
+ const u8 M_max = 4; /* 2 bits */
+ u8 N, K, M; /* multiplicators (e.g. N = n+1) */
+ u32 freq_mhz, steps_mhz, NxK;
+
+ freq_mhz = *freq / 1000000;
+
+ /* We will try to get the maximum resolution */
+ if (freq_mhz < parent_mhz*N_max*K_max/4)
+ M = 4;
+ else if (freq_mhz < parent_mhz*N_max*K_max/3)
+ M = 3;
+ else if (freq_mhz < parent_mhz*N_max*K_max/2)
+ M = 2;
else
- freq_mhz = round_freq_16;
+ M = 1;
- *freq = freq_mhz * 1000000;
+ steps_mhz = parent_mhz / M;
- /*
- * If the factors pointer are null, we were just called to
- * round down the frequency.
- * Exit.
- */
- if (n == NULL)
- return;
+ NxK = freq_mhz / steps_mhz;
- /* If the frequency is a multiple of 32 MHz, k is always 3 */
- if (!(freq_mhz % 32))
- *k = 3;
- /* If the frequency is a multiple of 9 MHz, k is always 2 */
- else if (!(freq_mhz % 9))
- *k = 2;
- /* If the frequency is a multiple of 8 MHz, k is always 1 */
- else if (!(freq_mhz % 8))
- *k = 1;
- /* Otherwise, we don't use the k factor */
+ /* We try to keep K as low as possible */
+ if (freq_mhz <= steps_mhz*N_max*1)
+ K = 1;
+ else if (freq_mhz <= steps_mhz*N_max*2)
+ K = 2;
+ else if (freq_mhz <= steps_mhz*N_max*3)
+ K = 3;
else
- *k = 0;
+ K = 4;
- /*
- * If the frequency is a multiple of 2 but not a multiple of
- * 3, m is 3. This is the first time we use 6 here, yet we
- * will use it on several other places.
- * We use this number because it's the lowest frequency we can
- * generate (with n = 0, k = 0, m = 3), so every other frequency
- * somehow relates to this frequency.
- */
- if ((freq_mhz % 6) == 2 || (freq_mhz % 6) == 4)
- *m = 2;
- /*
- * If the frequency is a multiple of 6MHz, but the factor is
- * odd, m will be 3
- */
- else if ((freq_mhz / 6) & 1)
- *m = 3;
- /* Otherwise, we end up with m = 1 */
- else
- *m = 1;
+ N = NxK / K;
- /* Calculate n thanks to the above factors we already got */
- *n = freq_mhz * (*m + 1) / ((*k + 1) * parent_freq_mhz) - 1;
+ *freq = (parent_rate * N * K) / M;
- /*
- * If n end up being outbound, and that we can still decrease
- * m, do it.
- */
- if ((*n + 1) > 31 && (*m + 1) > 1) {
- *n = (*n + 1) / 2 - 1;
- *m = (*m + 1) / 2 - 1;
+ if (n != NULL) {
+ *n = N-1;
+ *k = K-1;
+ *m = M-1;
}
}