aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-omap2/clock.c
diff options
context:
space:
mode:
authorPaul Walmsley <paul@pwsan.com>2010-01-26 22:13:03 -0500
committerPaul Walmsley <paul@pwsan.com>2010-01-26 22:13:03 -0500
commit0b96af683026ab9ca4dd52f9005a1a4fc582e914 (patch)
treebe435bd2d23d1607f034185763bf5840d244bab1 /arch/arm/mach-omap2/clock.c
parent98c4545749234393ec918b703f48eb708658a23d (diff)
OMAP2/3/4 clock: move DPLL clock functions into mach-omap2/clkt_dpll.c
Move all DPLL-related clock functions from mach-omap2/clock.c to mach-omap2/clkt_dpll.c. This is intended to make the clock code easier to understand, since all of the functions needed to manage DPLLs are now located in their own file, rather than being mixed with other, unrelated functions. Clock debugging is also now more finely-grained, since the DEBUG macro can now be defined for DPLLs alone. This should reduce unnecessary console noise when debugging. Also, if at some future point the mach-omap2/ directory is split into OMAP2/3/4 variants, this clkt file can be moved to the plat-omap/ directory to be shared. Thanks to Alexander Shishkin <virtuoso@slind.org> for his comments to improve the patch description. Signed-off-by: Paul Walmsley <paul@pwsan.com> Cc: Alexander Shishkin <virtuoso@slind.org>
Diffstat (limited to 'arch/arm/mach-omap2/clock.c')
-rw-r--r--arch/arm/mach-omap2/clock.c355
1 files changed, 0 insertions, 355 deletions
diff --git a/arch/arm/mach-omap2/clock.c b/arch/arm/mach-omap2/clock.c
index d88b25565a42..98196285e80c 100644
--- a/arch/arm/mach-omap2/clock.c
+++ b/arch/arm/mach-omap2/clock.c
@@ -28,10 +28,7 @@
28#include <plat/clockdomain.h> 28#include <plat/clockdomain.h>
29#include <plat/cpu.h> 29#include <plat/cpu.h>
30#include <plat/prcm.h> 30#include <plat/prcm.h>
31#include <asm/div64.h>
32 31
33#include <plat/sdrc.h>
34#include "sdrc.h"
35#include "clock.h" 32#include "clock.h"
36#include "prm.h" 33#include "prm.h"
37#include "prm-regbits-24xx.h" 34#include "prm-regbits-24xx.h"
@@ -39,72 +36,12 @@
39#include "cm-regbits-24xx.h" 36#include "cm-regbits-24xx.h"
40#include "cm-regbits-34xx.h" 37#include "cm-regbits-34xx.h"
41 38
42/* DPLL rate rounding: minimum DPLL multiplier, divider values */
43#define DPLL_MIN_MULTIPLIER 1
44#define DPLL_MIN_DIVIDER 1
45
46/* Possible error results from _dpll_test_mult */
47#define DPLL_MULT_UNDERFLOW -1
48
49/*
50 * Scale factor to mitigate roundoff errors in DPLL rate rounding.
51 * The higher the scale factor, the greater the risk of arithmetic overflow,
52 * but the closer the rounded rate to the target rate. DPLL_SCALE_FACTOR
53 * must be a power of DPLL_SCALE_BASE.
54 */
55#define DPLL_SCALE_FACTOR 64
56#define DPLL_SCALE_BASE 2
57#define DPLL_ROUNDING_VAL ((DPLL_SCALE_BASE / 2) * \
58 (DPLL_SCALE_FACTOR / DPLL_SCALE_BASE))
59
60/* DPLL valid Fint frequency band limits - from 34xx TRM Section 4.7.6.2 */
61#define DPLL_FINT_BAND1_MIN 750000
62#define DPLL_FINT_BAND1_MAX 2100000
63#define DPLL_FINT_BAND2_MIN 7500000
64#define DPLL_FINT_BAND2_MAX 21000000
65
66/* _dpll_test_fint() return codes */
67#define DPLL_FINT_UNDERFLOW -1
68#define DPLL_FINT_INVALID -2
69
70u8 cpu_mask; 39u8 cpu_mask;
71 40
72/*------------------------------------------------------------------------- 41/*-------------------------------------------------------------------------
73 * OMAP2/3/4 specific clock functions 42 * OMAP2/3/4 specific clock functions
74 *-------------------------------------------------------------------------*/ 43 *-------------------------------------------------------------------------*/
75 44
76void omap2_init_dpll_parent(struct clk *clk)
77{
78 u32 v;
79 struct dpll_data *dd;
80
81 dd = clk->dpll_data;
82 if (!dd)
83 return;
84
85 /* Return bypass rate if DPLL is bypassed */
86 v = __raw_readl(dd->control_reg);
87 v &= dd->enable_mask;
88 v >>= __ffs(dd->enable_mask);
89
90 /* Reparent in case the dpll is in bypass */
91 if (cpu_is_omap24xx()) {
92 if (v == OMAP2XXX_EN_DPLL_LPBYPASS ||
93 v == OMAP2XXX_EN_DPLL_FRBYPASS)
94 clk_reparent(clk, dd->clk_bypass);
95 } else if (cpu_is_omap34xx()) {
96 if (v == OMAP3XXX_EN_DPLL_LPBYPASS ||
97 v == OMAP3XXX_EN_DPLL_FRBYPASS)
98 clk_reparent(clk, dd->clk_bypass);
99 } else if (cpu_is_omap44xx()) {
100 if (v == OMAP4XXX_EN_DPLL_LPBYPASS ||
101 v == OMAP4XXX_EN_DPLL_FRBYPASS ||
102 v == OMAP4XXX_EN_DPLL_MNBYPASS)
103 clk_reparent(clk, dd->clk_bypass);
104 }
105 return;
106}
107
108/** 45/**
109 * _omap2xxx_clk_commit - commit clock parent/rate changes in hardware 46 * _omap2xxx_clk_commit - commit clock parent/rate changes in hardware
110 * @clk: struct clk * 47 * @clk: struct clk *
@@ -127,52 +64,6 @@ static void _omap2xxx_clk_commit(struct clk *clk)
127 prm_read_mod_reg(OMAP24XX_GR_MOD, OMAP2_PRCM_CLKCFG_CTRL_OFFSET); 64 prm_read_mod_reg(OMAP24XX_GR_MOD, OMAP2_PRCM_CLKCFG_CTRL_OFFSET);
128} 65}
129 66
130/*
131 * _dpll_test_fint - test whether an Fint value is valid for the DPLL
132 * @clk: DPLL struct clk to test
133 * @n: divider value (N) to test
134 *
135 * Tests whether a particular divider @n will result in a valid DPLL
136 * internal clock frequency Fint. See the 34xx TRM 4.7.6.2 "DPLL Jitter
137 * Correction". Returns 0 if OK, -1 if the enclosing loop can terminate
138 * (assuming that it is counting N upwards), or -2 if the enclosing loop
139 * should skip to the next iteration (again assuming N is increasing).
140 */
141static int _dpll_test_fint(struct clk *clk, u8 n)
142{
143 struct dpll_data *dd;
144 long fint;
145 int ret = 0;
146
147 dd = clk->dpll_data;
148
149 /* DPLL divider must result in a valid jitter correction val */
150 fint = clk->parent->rate / (n + 1);
151 if (fint < DPLL_FINT_BAND1_MIN) {
152
153 pr_debug("rejecting n=%d due to Fint failure, "
154 "lowering max_divider\n", n);
155 dd->max_divider = n;
156 ret = DPLL_FINT_UNDERFLOW;
157
158 } else if (fint > DPLL_FINT_BAND1_MAX &&
159 fint < DPLL_FINT_BAND2_MIN) {
160
161 pr_debug("rejecting n=%d due to Fint failure\n", n);
162 ret = DPLL_FINT_INVALID;
163
164 } else if (fint > DPLL_FINT_BAND2_MAX) {
165
166 pr_debug("rejecting n=%d due to Fint failure, "
167 "boosting min_divider\n", n);
168 dd->min_divider = n;
169 ret = DPLL_FINT_INVALID;
170
171 }
172
173 return ret;
174}
175
176/** 67/**
177 * omap2_init_clk_clkdm - look up a clockdomain name, store pointer in clk 68 * omap2_init_clk_clkdm - look up a clockdomain name, store pointer in clk
178 * @clk: OMAP clock struct ptr to use 69 * @clk: OMAP clock struct ptr to use
@@ -243,62 +134,6 @@ void omap2_init_clksel_parent(struct clk *clk)
243} 134}
244 135
245/** 136/**
246 * omap2_get_dpll_rate - returns the current DPLL CLKOUT rate
247 * @clk: struct clk * of a DPLL
248 *
249 * DPLLs can be locked or bypassed - basically, enabled or disabled.
250 * When locked, the DPLL output depends on the M and N values. When
251 * bypassed, on OMAP2xxx, the output rate is either the 32KiHz clock
252 * or sys_clk. Bypass rates on OMAP3 depend on the DPLL: DPLLs 1 and
253 * 2 are bypassed with dpll1_fclk and dpll2_fclk respectively
254 * (generated by DPLL3), while DPLL 3, 4, and 5 bypass rates are sys_clk.
255 * Returns the current DPLL CLKOUT rate (*not* CLKOUTX2) if the DPLL is
256 * locked, or the appropriate bypass rate if the DPLL is bypassed, or 0
257 * if the clock @clk is not a DPLL.
258 */
259u32 omap2_get_dpll_rate(struct clk *clk)
260{
261 long long dpll_clk;
262 u32 dpll_mult, dpll_div, v;
263 struct dpll_data *dd;
264
265 dd = clk->dpll_data;
266 if (!dd)
267 return 0;
268
269 /* Return bypass rate if DPLL is bypassed */
270 v = __raw_readl(dd->control_reg);
271 v &= dd->enable_mask;
272 v >>= __ffs(dd->enable_mask);
273
274 if (cpu_is_omap24xx()) {
275 if (v == OMAP2XXX_EN_DPLL_LPBYPASS ||
276 v == OMAP2XXX_EN_DPLL_FRBYPASS)
277 return dd->clk_bypass->rate;
278 } else if (cpu_is_omap34xx()) {
279 if (v == OMAP3XXX_EN_DPLL_LPBYPASS ||
280 v == OMAP3XXX_EN_DPLL_FRBYPASS)
281 return dd->clk_bypass->rate;
282 } else if (cpu_is_omap44xx()) {
283 if (v == OMAP4XXX_EN_DPLL_LPBYPASS ||
284 v == OMAP4XXX_EN_DPLL_FRBYPASS ||
285 v == OMAP4XXX_EN_DPLL_MNBYPASS)
286 return dd->clk_bypass->rate;
287 }
288
289 v = __raw_readl(dd->mult_div1_reg);
290 dpll_mult = v & dd->mult_mask;
291 dpll_mult >>= __ffs(dd->mult_mask);
292 dpll_div = v & dd->div1_mask;
293 dpll_div >>= __ffs(dd->div1_mask);
294
295 dpll_clk = (long long)dd->clk_ref->rate * dpll_mult;
296 do_div(dpll_clk, dpll_div + 1);
297
298 return dpll_clk;
299}
300
301/**
302 * omap2_clk_dflt_find_companion - find companion clock to @clk 137 * omap2_clk_dflt_find_companion - find companion clock to @clk
303 * @clk: struct clk * to find the companion clock of 138 * @clk: struct clk * to find the companion clock of
304 * @other_reg: void __iomem ** to return the companion clock CM_*CLKEN va in 139 * @other_reg: void __iomem ** to return the companion clock CM_*CLKEN va in
@@ -858,196 +693,6 @@ int omap2_clk_set_parent(struct clk *clk, struct clk *new_parent)
858 return 0; 693 return 0;
859} 694}
860 695
861/* DPLL rate rounding code */
862
863/**
864 * omap2_dpll_set_rate_tolerance: set the error tolerance during rate rounding
865 * @clk: struct clk * of the DPLL
866 * @tolerance: maximum rate error tolerance
867 *
868 * Set the maximum DPLL rate error tolerance for the rate rounding
869 * algorithm. The rate tolerance is an attempt to balance DPLL power
870 * saving (the least divider value "n") vs. rate fidelity (the least
871 * difference between the desired DPLL target rate and the rounded
872 * rate out of the algorithm). So, increasing the tolerance is likely
873 * to decrease DPLL power consumption and increase DPLL rate error.
874 * Returns -EINVAL if provided a null clock ptr or a clk that is not a
875 * DPLL; or 0 upon success.
876 */
877int omap2_dpll_set_rate_tolerance(struct clk *clk, unsigned int tolerance)
878{
879 if (!clk || !clk->dpll_data)
880 return -EINVAL;
881
882 clk->dpll_data->rate_tolerance = tolerance;
883
884 return 0;
885}
886
887static unsigned long _dpll_compute_new_rate(unsigned long parent_rate,
888 unsigned int m, unsigned int n)
889{
890 unsigned long long num;
891
892 num = (unsigned long long)parent_rate * m;
893 do_div(num, n);
894 return num;
895}
896
897/*
898 * _dpll_test_mult - test a DPLL multiplier value
899 * @m: pointer to the DPLL m (multiplier) value under test
900 * @n: current DPLL n (divider) value under test
901 * @new_rate: pointer to storage for the resulting rounded rate
902 * @target_rate: the desired DPLL rate
903 * @parent_rate: the DPLL's parent clock rate
904 *
905 * This code tests a DPLL multiplier value, ensuring that the
906 * resulting rate will not be higher than the target_rate, and that
907 * the multiplier value itself is valid for the DPLL. Initially, the
908 * integer pointed to by the m argument should be prescaled by
909 * multiplying by DPLL_SCALE_FACTOR. The code will replace this with
910 * a non-scaled m upon return. This non-scaled m will result in a
911 * new_rate as close as possible to target_rate (but not greater than
912 * target_rate) given the current (parent_rate, n, prescaled m)
913 * triple. Returns DPLL_MULT_UNDERFLOW in the event that the
914 * non-scaled m attempted to underflow, which can allow the calling
915 * function to bail out early; or 0 upon success.
916 */
917static int _dpll_test_mult(int *m, int n, unsigned long *new_rate,
918 unsigned long target_rate,
919 unsigned long parent_rate)
920{
921 int r = 0, carry = 0;
922
923 /* Unscale m and round if necessary */
924 if (*m % DPLL_SCALE_FACTOR >= DPLL_ROUNDING_VAL)
925 carry = 1;
926 *m = (*m / DPLL_SCALE_FACTOR) + carry;
927
928 /*
929 * The new rate must be <= the target rate to avoid programming
930 * a rate that is impossible for the hardware to handle
931 */
932 *new_rate = _dpll_compute_new_rate(parent_rate, *m, n);
933 if (*new_rate > target_rate) {
934 (*m)--;
935 *new_rate = 0;
936 }
937
938 /* Guard against m underflow */
939 if (*m < DPLL_MIN_MULTIPLIER) {
940 *m = DPLL_MIN_MULTIPLIER;
941 *new_rate = 0;
942 r = DPLL_MULT_UNDERFLOW;
943 }
944
945 if (*new_rate == 0)
946 *new_rate = _dpll_compute_new_rate(parent_rate, *m, n);
947
948 return r;
949}
950
951/**
952 * omap2_dpll_round_rate - round a target rate for an OMAP DPLL
953 * @clk: struct clk * for a DPLL
954 * @target_rate: desired DPLL clock rate
955 *
956 * Given a DPLL, a desired target rate, and a rate tolerance, round
957 * the target rate to a possible, programmable rate for this DPLL.
958 * Rate tolerance is assumed to be set by the caller before this
959 * function is called. Attempts to select the minimum possible n
960 * within the tolerance to reduce power consumption. Stores the
961 * computed (m, n) in the DPLL's dpll_data structure so set_rate()
962 * will not need to call this (expensive) function again. Returns ~0
963 * if the target rate cannot be rounded, either because the rate is
964 * too low or because the rate tolerance is set too tightly; or the
965 * rounded rate upon success.
966 */
967long omap2_dpll_round_rate(struct clk *clk, unsigned long target_rate)
968{
969 int m, n, r, e, scaled_max_m;
970 unsigned long scaled_rt_rp, new_rate;
971 int min_e = -1, min_e_m = -1, min_e_n = -1;
972 struct dpll_data *dd;
973
974 if (!clk || !clk->dpll_data)
975 return ~0;
976
977 dd = clk->dpll_data;
978
979 pr_debug("clock: starting DPLL round_rate for clock %s, target rate "
980 "%ld\n", clk->name, target_rate);
981
982 scaled_rt_rp = target_rate / (dd->clk_ref->rate / DPLL_SCALE_FACTOR);
983 scaled_max_m = dd->max_multiplier * DPLL_SCALE_FACTOR;
984
985 dd->last_rounded_rate = 0;
986
987 for (n = dd->min_divider; n <= dd->max_divider; n++) {
988
989 /* Is the (input clk, divider) pair valid for the DPLL? */
990 r = _dpll_test_fint(clk, n);
991 if (r == DPLL_FINT_UNDERFLOW)
992 break;
993 else if (r == DPLL_FINT_INVALID)
994 continue;
995
996 /* Compute the scaled DPLL multiplier, based on the divider */
997 m = scaled_rt_rp * n;
998
999 /*
1000 * Since we're counting n up, a m overflow means we
1001 * can bail out completely (since as n increases in
1002 * the next iteration, there's no way that m can
1003 * increase beyond the current m)
1004 */
1005 if (m > scaled_max_m)
1006 break;
1007
1008 r = _dpll_test_mult(&m, n, &new_rate, target_rate,
1009 dd->clk_ref->rate);
1010
1011 /* m can't be set low enough for this n - try with a larger n */
1012 if (r == DPLL_MULT_UNDERFLOW)
1013 continue;
1014
1015 e = target_rate - new_rate;
1016 pr_debug("clock: n = %d: m = %d: rate error is %d "
1017 "(new_rate = %ld)\n", n, m, e, new_rate);
1018
1019 if (min_e == -1 ||
1020 min_e >= (int)(abs(e) - dd->rate_tolerance)) {
1021 min_e = e;
1022 min_e_m = m;
1023 min_e_n = n;
1024
1025 pr_debug("clock: found new least error %d\n", min_e);
1026
1027 /* We found good settings -- bail out now */
1028 if (min_e <= dd->rate_tolerance)
1029 break;
1030 }
1031 }
1032
1033 if (min_e < 0) {
1034 pr_debug("clock: error: target rate or tolerance too low\n");
1035 return ~0;
1036 }
1037
1038 dd->last_rounded_m = min_e_m;
1039 dd->last_rounded_n = min_e_n;
1040 dd->last_rounded_rate = _dpll_compute_new_rate(dd->clk_ref->rate,
1041 min_e_m, min_e_n);
1042
1043 pr_debug("clock: final least error: e = %d, m = %d, n = %d\n",
1044 min_e, min_e_m, min_e_n);
1045 pr_debug("clock: final rate: %ld (target rate: %ld)\n",
1046 dd->last_rounded_rate, target_rate);
1047
1048 return dd->last_rounded_rate;
1049}
1050
1051/*------------------------------------------------------------------------- 696/*-------------------------------------------------------------------------
1052 * Omap2 clock reset and init functions 697 * Omap2 clock reset and init functions
1053 *-------------------------------------------------------------------------*/ 698 *-------------------------------------------------------------------------*/