diff options
author | Christoph Muellner <christoph.muellner@theobroma-systems.com> | 2015-05-05 22:50:26 +0200 |
---|---|---|
committer | Klaus Goger <klaus.goger@theobroma-systems.com> | 2015-07-30 18:52:57 +0200 |
commit | db74f63aa29c867c76e5578674355d3ef6b82a96 (patch) | |
tree | 89e5d8d49b1c99c74f9730ab07a4ab04b0379f4f | |
parent | 7ce3d59bcfbf650de4116a2bdf83c69de2267e0a (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.c | 97 |
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; } } |