diff options
Diffstat (limited to 'arch/arm/mach-omap2/clock.c')
-rw-r--r-- | arch/arm/mach-omap2/clock.c | 992 |
1 files changed, 221 insertions, 771 deletions
diff --git a/arch/arm/mach-omap2/clock.c b/arch/arm/mach-omap2/clock.c index f2a92d614f0f..a6d0b34b7990 100644 --- a/arch/arm/mach-omap2/clock.c +++ b/arch/arm/mach-omap2/clock.c | |||
@@ -2,7 +2,7 @@ | |||
2 | * linux/arch/arm/mach-omap2/clock.c | 2 | * linux/arch/arm/mach-omap2/clock.c |
3 | * | 3 | * |
4 | * Copyright (C) 2005-2008 Texas Instruments, Inc. | 4 | * Copyright (C) 2005-2008 Texas Instruments, Inc. |
5 | * Copyright (C) 2004-2008 Nokia Corporation | 5 | * Copyright (C) 2004-2010 Nokia Corporation |
6 | * | 6 | * |
7 | * Contacts: | 7 | * Contacts: |
8 | * Richard Woodruff <r-woodruff2@ti.com> | 8 | * Richard Woodruff <r-woodruff2@ti.com> |
@@ -14,24 +14,20 @@ | |||
14 | */ | 14 | */ |
15 | #undef DEBUG | 15 | #undef DEBUG |
16 | 16 | ||
17 | #include <linux/module.h> | ||
18 | #include <linux/kernel.h> | 17 | #include <linux/kernel.h> |
19 | #include <linux/device.h> | ||
20 | #include <linux/list.h> | 18 | #include <linux/list.h> |
21 | #include <linux/errno.h> | 19 | #include <linux/errno.h> |
20 | #include <linux/err.h> | ||
22 | #include <linux/delay.h> | 21 | #include <linux/delay.h> |
23 | #include <linux/clk.h> | 22 | #include <linux/clk.h> |
24 | #include <linux/io.h> | 23 | #include <linux/io.h> |
25 | #include <linux/bitops.h> | 24 | #include <linux/bitops.h> |
26 | 25 | ||
27 | #include <mach/clock.h> | 26 | #include <plat/clock.h> |
28 | #include <mach/clockdomain.h> | 27 | #include <plat/clockdomain.h> |
29 | #include <mach/cpu.h> | 28 | #include <plat/cpu.h> |
30 | #include <mach/prcm.h> | 29 | #include <plat/prcm.h> |
31 | #include <asm/div64.h> | ||
32 | 30 | ||
33 | #include <mach/sdrc.h> | ||
34 | #include "sdrc.h" | ||
35 | #include "clock.h" | 31 | #include "clock.h" |
36 | #include "prm.h" | 32 | #include "prm.h" |
37 | #include "prm-regbits-24xx.h" | 33 | #include "prm-regbits-24xx.h" |
@@ -39,108 +35,44 @@ | |||
39 | #include "cm-regbits-24xx.h" | 35 | #include "cm-regbits-24xx.h" |
40 | #include "cm-regbits-34xx.h" | 36 | #include "cm-regbits-34xx.h" |
41 | 37 | ||
42 | /* DPLL rate rounding: minimum DPLL multiplier, divider values */ | 38 | u8 cpu_mask; |
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 | 39 | ||
49 | /* | 40 | /* |
50 | * Scale factor to mitigate roundoff errors in DPLL rate rounding. | 41 | * OMAP2+ specific clock functions |
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 | */ | 42 | */ |
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 | |||
70 | u8 cpu_mask; | ||
71 | 43 | ||
72 | /*------------------------------------------------------------------------- | 44 | /* Private functions */ |
73 | * OMAP2/3 specific clock functions | ||
74 | *-------------------------------------------------------------------------*/ | ||
75 | 45 | ||
76 | /** | 46 | /** |
77 | * _omap2xxx_clk_commit - commit clock parent/rate changes in hardware | 47 | * _omap2_module_wait_ready - wait for an OMAP module to leave IDLE |
78 | * @clk: struct clk * | 48 | * @clk: struct clk * belonging to the module |
79 | * | ||
80 | * If @clk has the DELAYED_APP flag set, meaning that parent/rate changes | ||
81 | * don't take effect until the VALID_CONFIG bit is written, write the | ||
82 | * VALID_CONFIG bit and wait for the write to complete. No return value. | ||
83 | */ | ||
84 | static void _omap2xxx_clk_commit(struct clk *clk) | ||
85 | { | ||
86 | if (!cpu_is_omap24xx()) | ||
87 | return; | ||
88 | |||
89 | if (!(clk->flags & DELAYED_APP)) | ||
90 | return; | ||
91 | |||
92 | prm_write_mod_reg(OMAP24XX_VALID_CONFIG, OMAP24XX_GR_MOD, | ||
93 | OMAP2_PRCM_CLKCFG_CTRL_OFFSET); | ||
94 | /* OCP barrier */ | ||
95 | prm_read_mod_reg(OMAP24XX_GR_MOD, OMAP2_PRCM_CLKCFG_CTRL_OFFSET); | ||
96 | } | ||
97 | |||
98 | /* | ||
99 | * _dpll_test_fint - test whether an Fint value is valid for the DPLL | ||
100 | * @clk: DPLL struct clk to test | ||
101 | * @n: divider value (N) to test | ||
102 | * | 49 | * |
103 | * Tests whether a particular divider @n will result in a valid DPLL | 50 | * If the necessary clocks for the OMAP hardware IP block that |
104 | * internal clock frequency Fint. See the 34xx TRM 4.7.6.2 "DPLL Jitter | 51 | * corresponds to clock @clk are enabled, then wait for the module to |
105 | * Correction". Returns 0 if OK, -1 if the enclosing loop can terminate | 52 | * indicate readiness (i.e., to leave IDLE). This code does not |
106 | * (assuming that it is counting N upwards), or -2 if the enclosing loop | 53 | * belong in the clock code and will be moved in the medium term to |
107 | * should skip to the next iteration (again assuming N is increasing). | 54 | * module-dependent code. No return value. |
108 | */ | 55 | */ |
109 | static int _dpll_test_fint(struct clk *clk, u8 n) | 56 | static void _omap2_module_wait_ready(struct clk *clk) |
110 | { | 57 | { |
111 | struct dpll_data *dd; | 58 | void __iomem *companion_reg, *idlest_reg; |
112 | long fint; | 59 | u8 other_bit, idlest_bit, idlest_val; |
113 | int ret = 0; | ||
114 | |||
115 | dd = clk->dpll_data; | ||
116 | |||
117 | /* DPLL divider must result in a valid jitter correction val */ | ||
118 | fint = clk->parent->rate / (n + 1); | ||
119 | if (fint < DPLL_FINT_BAND1_MIN) { | ||
120 | |||
121 | pr_debug("rejecting n=%d due to Fint failure, " | ||
122 | "lowering max_divider\n", n); | ||
123 | dd->max_divider = n; | ||
124 | ret = DPLL_FINT_UNDERFLOW; | ||
125 | |||
126 | } else if (fint > DPLL_FINT_BAND1_MAX && | ||
127 | fint < DPLL_FINT_BAND2_MIN) { | ||
128 | |||
129 | pr_debug("rejecting n=%d due to Fint failure\n", n); | ||
130 | ret = DPLL_FINT_INVALID; | ||
131 | |||
132 | } else if (fint > DPLL_FINT_BAND2_MAX) { | ||
133 | |||
134 | pr_debug("rejecting n=%d due to Fint failure, " | ||
135 | "boosting min_divider\n", n); | ||
136 | dd->min_divider = n; | ||
137 | ret = DPLL_FINT_INVALID; | ||
138 | 60 | ||
61 | /* Not all modules have multiple clocks that their IDLEST depends on */ | ||
62 | if (clk->ops->find_companion) { | ||
63 | clk->ops->find_companion(clk, &companion_reg, &other_bit); | ||
64 | if (!(__raw_readl(companion_reg) & (1 << other_bit))) | ||
65 | return; | ||
139 | } | 66 | } |
140 | 67 | ||
141 | return ret; | 68 | clk->ops->find_idlest(clk, &idlest_reg, &idlest_bit, &idlest_val); |
69 | |||
70 | omap2_cm_wait_idlest(idlest_reg, (1 << idlest_bit), idlest_val, | ||
71 | clk->name); | ||
142 | } | 72 | } |
143 | 73 | ||
74 | /* Public functions */ | ||
75 | |||
144 | /** | 76 | /** |
145 | * omap2_init_clk_clkdm - look up a clockdomain name, store pointer in clk | 77 | * omap2_init_clk_clkdm - look up a clockdomain name, store pointer in clk |
146 | * @clk: OMAP clock struct ptr to use | 78 | * @clk: OMAP clock struct ptr to use |
@@ -168,111 +100,6 @@ void omap2_init_clk_clkdm(struct clk *clk) | |||
168 | } | 100 | } |
169 | 101 | ||
170 | /** | 102 | /** |
171 | * omap2_init_clksel_parent - set a clksel clk's parent field from the hardware | ||
172 | * @clk: OMAP clock struct ptr to use | ||
173 | * | ||
174 | * Given a pointer to a source-selectable struct clk, read the hardware | ||
175 | * register and determine what its parent is currently set to. Update the | ||
176 | * clk->parent field with the appropriate clk ptr. | ||
177 | */ | ||
178 | void omap2_init_clksel_parent(struct clk *clk) | ||
179 | { | ||
180 | const struct clksel *clks; | ||
181 | const struct clksel_rate *clkr; | ||
182 | u32 r, found = 0; | ||
183 | |||
184 | if (!clk->clksel) | ||
185 | return; | ||
186 | |||
187 | r = __raw_readl(clk->clksel_reg) & clk->clksel_mask; | ||
188 | r >>= __ffs(clk->clksel_mask); | ||
189 | |||
190 | for (clks = clk->clksel; clks->parent && !found; clks++) { | ||
191 | for (clkr = clks->rates; clkr->div && !found; clkr++) { | ||
192 | if ((clkr->flags & cpu_mask) && (clkr->val == r)) { | ||
193 | if (clk->parent != clks->parent) { | ||
194 | pr_debug("clock: inited %s parent " | ||
195 | "to %s (was %s)\n", | ||
196 | clk->name, clks->parent->name, | ||
197 | ((clk->parent) ? | ||
198 | clk->parent->name : "NULL")); | ||
199 | clk_reparent(clk, clks->parent); | ||
200 | }; | ||
201 | found = 1; | ||
202 | } | ||
203 | } | ||
204 | } | ||
205 | |||
206 | if (!found) | ||
207 | printk(KERN_ERR "clock: init parent: could not find " | ||
208 | "regval %0x for clock %s\n", r, clk->name); | ||
209 | |||
210 | return; | ||
211 | } | ||
212 | |||
213 | /** | ||
214 | * omap2_get_dpll_rate - returns the current DPLL CLKOUT rate | ||
215 | * @clk: struct clk * of a DPLL | ||
216 | * | ||
217 | * DPLLs can be locked or bypassed - basically, enabled or disabled. | ||
218 | * When locked, the DPLL output depends on the M and N values. When | ||
219 | * bypassed, on OMAP2xxx, the output rate is either the 32KiHz clock | ||
220 | * or sys_clk. Bypass rates on OMAP3 depend on the DPLL: DPLLs 1 and | ||
221 | * 2 are bypassed with dpll1_fclk and dpll2_fclk respectively | ||
222 | * (generated by DPLL3), while DPLL 3, 4, and 5 bypass rates are sys_clk. | ||
223 | * Returns the current DPLL CLKOUT rate (*not* CLKOUTX2) if the DPLL is | ||
224 | * locked, or the appropriate bypass rate if the DPLL is bypassed, or 0 | ||
225 | * if the clock @clk is not a DPLL. | ||
226 | */ | ||
227 | u32 omap2_get_dpll_rate(struct clk *clk) | ||
228 | { | ||
229 | long long dpll_clk; | ||
230 | u32 dpll_mult, dpll_div, v; | ||
231 | struct dpll_data *dd; | ||
232 | |||
233 | dd = clk->dpll_data; | ||
234 | if (!dd) | ||
235 | return 0; | ||
236 | |||
237 | /* Return bypass rate if DPLL is bypassed */ | ||
238 | v = __raw_readl(dd->control_reg); | ||
239 | v &= dd->enable_mask; | ||
240 | v >>= __ffs(dd->enable_mask); | ||
241 | |||
242 | if (cpu_is_omap24xx()) { | ||
243 | if (v == OMAP2XXX_EN_DPLL_LPBYPASS || | ||
244 | v == OMAP2XXX_EN_DPLL_FRBYPASS) | ||
245 | return dd->clk_bypass->rate; | ||
246 | } else if (cpu_is_omap34xx()) { | ||
247 | if (v == OMAP3XXX_EN_DPLL_LPBYPASS || | ||
248 | v == OMAP3XXX_EN_DPLL_FRBYPASS) | ||
249 | return dd->clk_bypass->rate; | ||
250 | } | ||
251 | |||
252 | v = __raw_readl(dd->mult_div1_reg); | ||
253 | dpll_mult = v & dd->mult_mask; | ||
254 | dpll_mult >>= __ffs(dd->mult_mask); | ||
255 | dpll_div = v & dd->div1_mask; | ||
256 | dpll_div >>= __ffs(dd->div1_mask); | ||
257 | |||
258 | dpll_clk = (long long)dd->clk_ref->rate * dpll_mult; | ||
259 | do_div(dpll_clk, dpll_div + 1); | ||
260 | |||
261 | return dpll_clk; | ||
262 | } | ||
263 | |||
264 | /* | ||
265 | * Used for clocks that have the same value as the parent clock, | ||
266 | * divided by some factor | ||
267 | */ | ||
268 | unsigned long omap2_fixed_divisor_recalc(struct clk *clk) | ||
269 | { | ||
270 | WARN_ON(!clk->fixed_div); | ||
271 | |||
272 | return clk->parent->rate / clk->fixed_div; | ||
273 | } | ||
274 | |||
275 | /** | ||
276 | * omap2_clk_dflt_find_companion - find companion clock to @clk | 103 | * omap2_clk_dflt_find_companion - find companion clock to @clk |
277 | * @clk: struct clk * to find the companion clock of | 104 | * @clk: struct clk * to find the companion clock of |
278 | * @other_reg: void __iomem ** to return the companion clock CM_*CLKEN va in | 105 | * @other_reg: void __iomem ** to return the companion clock CM_*CLKEN va in |
@@ -312,7 +139,8 @@ void omap2_clk_dflt_find_companion(struct clk *clk, void __iomem **other_reg, | |||
312 | * omap2_clk_dflt_find_idlest - find CM_IDLEST reg va, bit shift for @clk | 139 | * omap2_clk_dflt_find_idlest - find CM_IDLEST reg va, bit shift for @clk |
313 | * @clk: struct clk * to find IDLEST info for | 140 | * @clk: struct clk * to find IDLEST info for |
314 | * @idlest_reg: void __iomem ** to return the CM_IDLEST va in | 141 | * @idlest_reg: void __iomem ** to return the CM_IDLEST va in |
315 | * @idlest_bit: u8 ** to return the CM_IDLEST bit shift in | 142 | * @idlest_bit: u8 * to return the CM_IDLEST bit shift in |
143 | * @idlest_val: u8 * to return the idle status indicator | ||
316 | * | 144 | * |
317 | * Return the CM_IDLEST register address and bit shift corresponding | 145 | * Return the CM_IDLEST register address and bit shift corresponding |
318 | * to the module that "owns" this clock. This default code assumes | 146 | * to the module that "owns" this clock. This default code assumes |
@@ -322,40 +150,26 @@ void omap2_clk_dflt_find_companion(struct clk *clk, void __iomem **other_reg, | |||
322 | * CM_IDLEST2). This is not true for all modules. No return value. | 150 | * CM_IDLEST2). This is not true for all modules. No return value. |
323 | */ | 151 | */ |
324 | void omap2_clk_dflt_find_idlest(struct clk *clk, void __iomem **idlest_reg, | 152 | void omap2_clk_dflt_find_idlest(struct clk *clk, void __iomem **idlest_reg, |
325 | u8 *idlest_bit) | 153 | u8 *idlest_bit, u8 *idlest_val) |
326 | { | 154 | { |
327 | u32 r; | 155 | u32 r; |
328 | 156 | ||
329 | r = (((__force u32)clk->enable_reg & ~0xf0) | 0x20); | 157 | r = (((__force u32)clk->enable_reg & ~0xf0) | 0x20); |
330 | *idlest_reg = (__force void __iomem *)r; | 158 | *idlest_reg = (__force void __iomem *)r; |
331 | *idlest_bit = clk->enable_bit; | 159 | *idlest_bit = clk->enable_bit; |
332 | } | ||
333 | 160 | ||
334 | /** | 161 | /* |
335 | * omap2_module_wait_ready - wait for an OMAP module to leave IDLE | 162 | * 24xx uses 0 to indicate not ready, and 1 to indicate ready. |
336 | * @clk: struct clk * belonging to the module | 163 | * 34xx reverses this, just to keep us on our toes |
337 | * | 164 | * AM35xx uses both, depending on the module. |
338 | * If the necessary clocks for the OMAP hardware IP block that | 165 | */ |
339 | * corresponds to clock @clk are enabled, then wait for the module to | 166 | if (cpu_is_omap24xx()) |
340 | * indicate readiness (i.e., to leave IDLE). This code does not | 167 | *idlest_val = OMAP24XX_CM_IDLEST_VAL; |
341 | * belong in the clock code and will be moved in the medium term to | 168 | else if (cpu_is_omap34xx()) |
342 | * module-dependent code. No return value. | 169 | *idlest_val = OMAP34XX_CM_IDLEST_VAL; |
343 | */ | 170 | else |
344 | static void omap2_module_wait_ready(struct clk *clk) | 171 | BUG(); |
345 | { | ||
346 | void __iomem *companion_reg, *idlest_reg; | ||
347 | u8 other_bit, idlest_bit; | ||
348 | |||
349 | /* Not all modules have multiple clocks that their IDLEST depends on */ | ||
350 | if (clk->ops->find_companion) { | ||
351 | clk->ops->find_companion(clk, &companion_reg, &other_bit); | ||
352 | if (!(__raw_readl(companion_reg) & (1 << other_bit))) | ||
353 | return; | ||
354 | } | ||
355 | |||
356 | clk->ops->find_idlest(clk, &idlest_reg, &idlest_bit); | ||
357 | 172 | ||
358 | omap2_cm_wait_idlest(idlest_reg, (1 << idlest_bit), clk->name); | ||
359 | } | 173 | } |
360 | 174 | ||
361 | int omap2_dflt_clk_enable(struct clk *clk) | 175 | int omap2_dflt_clk_enable(struct clk *clk) |
@@ -377,7 +191,7 @@ int omap2_dflt_clk_enable(struct clk *clk) | |||
377 | v = __raw_readl(clk->enable_reg); /* OCP barrier */ | 191 | v = __raw_readl(clk->enable_reg); /* OCP barrier */ |
378 | 192 | ||
379 | if (clk->ops->find_idlest) | 193 | if (clk->ops->find_idlest) |
380 | omap2_module_wait_ready(clk); | 194 | _omap2_module_wait_ready(clk); |
381 | 195 | ||
382 | return 0; | 196 | return 0; |
383 | } | 197 | } |
@@ -417,331 +231,109 @@ const struct clkops clkops_omap2_dflt = { | |||
417 | .disable = omap2_dflt_clk_disable, | 231 | .disable = omap2_dflt_clk_disable, |
418 | }; | 232 | }; |
419 | 233 | ||
420 | /* Enables clock without considering parent dependencies or use count | 234 | /** |
421 | * REVISIT: Maybe change this to use clk->enable like on omap1? | 235 | * omap2_clk_disable - disable a clock, if the system is not using it |
236 | * @clk: struct clk * to disable | ||
237 | * | ||
238 | * Decrements the usecount on struct clk @clk. If there are no users | ||
239 | * left, call the clkops-specific clock disable function to disable it | ||
240 | * in hardware. If the clock is part of a clockdomain (which they all | ||
241 | * should be), request that the clockdomain be disabled. (It too has | ||
242 | * a usecount, and so will not be disabled in the hardware until it no | ||
243 | * longer has any users.) If the clock has a parent clock (most of | ||
244 | * them do), then call ourselves, recursing on the parent clock. This | ||
245 | * can cause an entire branch of the clock tree to be powered off by | ||
246 | * simply disabling one clock. Intended to be called with the clockfw_lock | ||
247 | * spinlock held. No return value. | ||
422 | */ | 248 | */ |
423 | static int _omap2_clk_enable(struct clk *clk) | ||
424 | { | ||
425 | return clk->ops->enable(clk); | ||
426 | } | ||
427 | |||
428 | /* Disables clock without considering parent dependencies or use count */ | ||
429 | static void _omap2_clk_disable(struct clk *clk) | ||
430 | { | ||
431 | clk->ops->disable(clk); | ||
432 | } | ||
433 | |||
434 | void omap2_clk_disable(struct clk *clk) | 249 | void omap2_clk_disable(struct clk *clk) |
435 | { | 250 | { |
436 | if (clk->usecount > 0 && !(--clk->usecount)) { | 251 | if (clk->usecount == 0) { |
437 | _omap2_clk_disable(clk); | 252 | WARN(1, "clock: %s: omap2_clk_disable() called, but usecount " |
438 | if (clk->parent) | 253 | "already 0?", clk->name); |
439 | omap2_clk_disable(clk->parent); | 254 | return; |
440 | if (clk->clkdm) | ||
441 | omap2_clkdm_clk_disable(clk->clkdm, clk); | ||
442 | |||
443 | } | 255 | } |
444 | } | ||
445 | 256 | ||
446 | int omap2_clk_enable(struct clk *clk) | 257 | pr_debug("clock: %s: decrementing usecount\n", clk->name); |
447 | { | ||
448 | int ret = 0; | ||
449 | 258 | ||
450 | if (clk->usecount++ == 0) { | 259 | clk->usecount--; |
451 | if (clk->clkdm) | ||
452 | omap2_clkdm_clk_enable(clk->clkdm, clk); | ||
453 | 260 | ||
454 | if (clk->parent) { | 261 | if (clk->usecount > 0) |
455 | ret = omap2_clk_enable(clk->parent); | 262 | return; |
456 | if (ret) | ||
457 | goto err; | ||
458 | } | ||
459 | 263 | ||
460 | ret = _omap2_clk_enable(clk); | 264 | pr_debug("clock: %s: disabling in hardware\n", clk->name); |
461 | if (ret) { | ||
462 | if (clk->parent) | ||
463 | omap2_clk_disable(clk->parent); | ||
464 | 265 | ||
465 | goto err; | 266 | clk->ops->disable(clk); |
466 | } | ||
467 | } | ||
468 | return ret; | ||
469 | 267 | ||
470 | err: | ||
471 | if (clk->clkdm) | 268 | if (clk->clkdm) |
472 | omap2_clkdm_clk_disable(clk->clkdm, clk); | 269 | omap2_clkdm_clk_disable(clk->clkdm, clk); |
473 | clk->usecount--; | ||
474 | return ret; | ||
475 | } | ||
476 | 270 | ||
477 | /* | 271 | if (clk->parent) |
478 | * Used for clocks that are part of CLKSEL_xyz governed clocks. | 272 | omap2_clk_disable(clk->parent); |
479 | * REVISIT: Maybe change to use clk->enable() functions like on omap1? | ||
480 | */ | ||
481 | unsigned long omap2_clksel_recalc(struct clk *clk) | ||
482 | { | ||
483 | unsigned long rate; | ||
484 | u32 div = 0; | ||
485 | |||
486 | pr_debug("clock: recalc'ing clksel clk %s\n", clk->name); | ||
487 | |||
488 | div = omap2_clksel_get_divisor(clk); | ||
489 | if (div == 0) | ||
490 | return clk->rate; | ||
491 | |||
492 | rate = clk->parent->rate / div; | ||
493 | |||
494 | pr_debug("clock: new clock rate is %ld (div %d)\n", rate, div); | ||
495 | |||
496 | return rate; | ||
497 | } | ||
498 | |||
499 | /** | ||
500 | * omap2_get_clksel_by_parent - return clksel struct for a given clk & parent | ||
501 | * @clk: OMAP struct clk ptr to inspect | ||
502 | * @src_clk: OMAP struct clk ptr of the parent clk to search for | ||
503 | * | ||
504 | * Scan the struct clksel array associated with the clock to find | ||
505 | * the element associated with the supplied parent clock address. | ||
506 | * Returns a pointer to the struct clksel on success or NULL on error. | ||
507 | */ | ||
508 | static const struct clksel *omap2_get_clksel_by_parent(struct clk *clk, | ||
509 | struct clk *src_clk) | ||
510 | { | ||
511 | const struct clksel *clks; | ||
512 | |||
513 | if (!clk->clksel) | ||
514 | return NULL; | ||
515 | |||
516 | for (clks = clk->clksel; clks->parent; clks++) { | ||
517 | if (clks->parent == src_clk) | ||
518 | break; /* Found the requested parent */ | ||
519 | } | ||
520 | |||
521 | if (!clks->parent) { | ||
522 | printk(KERN_ERR "clock: Could not find parent clock %s in " | ||
523 | "clksel array of clock %s\n", src_clk->name, | ||
524 | clk->name); | ||
525 | return NULL; | ||
526 | } | ||
527 | |||
528 | return clks; | ||
529 | } | 273 | } |
530 | 274 | ||
531 | /** | 275 | /** |
532 | * omap2_clksel_round_rate_div - find divisor for the given clock and rate | 276 | * omap2_clk_enable - request that the system enable a clock |
533 | * @clk: OMAP struct clk to use | 277 | * @clk: struct clk * to enable |
534 | * @target_rate: desired clock rate | ||
535 | * @new_div: ptr to where we should store the divisor | ||
536 | * | ||
537 | * Finds 'best' divider value in an array based on the source and target | ||
538 | * rates. The divider array must be sorted with smallest divider first. | ||
539 | * Note that this will not work for clocks which are part of CONFIG_PARTICIPANT, | ||
540 | * they are only settable as part of virtual_prcm set. | ||
541 | * | 278 | * |
542 | * Returns the rounded clock rate or returns 0xffffffff on error. | 279 | * Increments the usecount on struct clk @clk. If there were no users |
280 | * previously, then recurse up the clock tree, enabling all of the | ||
281 | * clock's parents and all of the parent clockdomains, and finally, | ||
282 | * enabling @clk's clockdomain, and @clk itself. Intended to be | ||
283 | * called with the clockfw_lock spinlock held. Returns 0 upon success | ||
284 | * or a negative error code upon failure. | ||
543 | */ | 285 | */ |
544 | u32 omap2_clksel_round_rate_div(struct clk *clk, unsigned long target_rate, | 286 | int omap2_clk_enable(struct clk *clk) |
545 | u32 *new_div) | ||
546 | { | ||
547 | unsigned long test_rate; | ||
548 | const struct clksel *clks; | ||
549 | const struct clksel_rate *clkr; | ||
550 | u32 last_div = 0; | ||
551 | |||
552 | pr_debug("clock: clksel_round_rate_div: %s target_rate %ld\n", | ||
553 | clk->name, target_rate); | ||
554 | |||
555 | *new_div = 1; | ||
556 | |||
557 | clks = omap2_get_clksel_by_parent(clk, clk->parent); | ||
558 | if (!clks) | ||
559 | return ~0; | ||
560 | |||
561 | for (clkr = clks->rates; clkr->div; clkr++) { | ||
562 | if (!(clkr->flags & cpu_mask)) | ||
563 | continue; | ||
564 | |||
565 | /* Sanity check */ | ||
566 | if (clkr->div <= last_div) | ||
567 | pr_err("clock: clksel_rate table not sorted " | ||
568 | "for clock %s", clk->name); | ||
569 | |||
570 | last_div = clkr->div; | ||
571 | |||
572 | test_rate = clk->parent->rate / clkr->div; | ||
573 | |||
574 | if (test_rate <= target_rate) | ||
575 | break; /* found it */ | ||
576 | } | ||
577 | |||
578 | if (!clkr->div) { | ||
579 | pr_err("clock: Could not find divisor for target " | ||
580 | "rate %ld for clock %s parent %s\n", target_rate, | ||
581 | clk->name, clk->parent->name); | ||
582 | return ~0; | ||
583 | } | ||
584 | |||
585 | *new_div = clkr->div; | ||
586 | |||
587 | pr_debug("clock: new_div = %d, new_rate = %ld\n", *new_div, | ||
588 | (clk->parent->rate / clkr->div)); | ||
589 | |||
590 | return (clk->parent->rate / clkr->div); | ||
591 | } | ||
592 | |||
593 | /** | ||
594 | * omap2_clksel_round_rate - find rounded rate for the given clock and rate | ||
595 | * @clk: OMAP struct clk to use | ||
596 | * @target_rate: desired clock rate | ||
597 | * | ||
598 | * Compatibility wrapper for OMAP clock framework | ||
599 | * Finds best target rate based on the source clock and possible dividers. | ||
600 | * rates. The divider array must be sorted with smallest divider first. | ||
601 | * Note that this will not work for clocks which are part of CONFIG_PARTICIPANT, | ||
602 | * they are only settable as part of virtual_prcm set. | ||
603 | * | ||
604 | * Returns the rounded clock rate or returns 0xffffffff on error. | ||
605 | */ | ||
606 | long omap2_clksel_round_rate(struct clk *clk, unsigned long target_rate) | ||
607 | { | ||
608 | u32 new_div; | ||
609 | |||
610 | return omap2_clksel_round_rate_div(clk, target_rate, &new_div); | ||
611 | } | ||
612 | |||
613 | |||
614 | /* Given a clock and a rate apply a clock specific rounding function */ | ||
615 | long omap2_clk_round_rate(struct clk *clk, unsigned long rate) | ||
616 | { | 287 | { |
617 | if (clk->round_rate) | 288 | int ret; |
618 | return clk->round_rate(clk, rate); | ||
619 | 289 | ||
620 | if (clk->flags & RATE_FIXED) | 290 | pr_debug("clock: %s: incrementing usecount\n", clk->name); |
621 | printk(KERN_ERR "clock: generic omap2_clk_round_rate called " | ||
622 | "on fixed-rate clock %s\n", clk->name); | ||
623 | 291 | ||
624 | return clk->rate; | 292 | clk->usecount++; |
625 | } | ||
626 | 293 | ||
627 | /** | 294 | if (clk->usecount > 1) |
628 | * omap2_clksel_to_divisor() - turn clksel field value into integer divider | ||
629 | * @clk: OMAP struct clk to use | ||
630 | * @field_val: register field value to find | ||
631 | * | ||
632 | * Given a struct clk of a rate-selectable clksel clock, and a register field | ||
633 | * value to search for, find the corresponding clock divisor. The register | ||
634 | * field value should be pre-masked and shifted down so the LSB is at bit 0 | ||
635 | * before calling. Returns 0 on error | ||
636 | */ | ||
637 | u32 omap2_clksel_to_divisor(struct clk *clk, u32 field_val) | ||
638 | { | ||
639 | const struct clksel *clks; | ||
640 | const struct clksel_rate *clkr; | ||
641 | |||
642 | clks = omap2_get_clksel_by_parent(clk, clk->parent); | ||
643 | if (!clks) | ||
644 | return 0; | 295 | return 0; |
645 | 296 | ||
646 | for (clkr = clks->rates; clkr->div; clkr++) { | 297 | pr_debug("clock: %s: enabling in hardware\n", clk->name); |
647 | if ((clkr->flags & cpu_mask) && (clkr->val == field_val)) | ||
648 | break; | ||
649 | } | ||
650 | 298 | ||
651 | if (!clkr->div) { | 299 | if (clk->parent) { |
652 | printk(KERN_ERR "clock: Could not find fieldval %d for " | 300 | ret = omap2_clk_enable(clk->parent); |
653 | "clock %s parent %s\n", field_val, clk->name, | 301 | if (ret) { |
654 | clk->parent->name); | 302 | WARN(1, "clock: %s: could not enable parent %s: %d\n", |
655 | return 0; | 303 | clk->name, clk->parent->name, ret); |
304 | goto oce_err1; | ||
305 | } | ||
656 | } | 306 | } |
657 | 307 | ||
658 | return clkr->div; | 308 | if (clk->clkdm) { |
659 | } | 309 | ret = omap2_clkdm_clk_enable(clk->clkdm, clk); |
660 | 310 | if (ret) { | |
661 | /** | 311 | WARN(1, "clock: %s: could not enable clockdomain %s: " |
662 | * omap2_divisor_to_clksel() - turn clksel integer divisor into a field value | 312 | "%d\n", clk->name, clk->clkdm->name, ret); |
663 | * @clk: OMAP struct clk to use | 313 | goto oce_err2; |
664 | * @div: integer divisor to search for | 314 | } |
665 | * | ||
666 | * Given a struct clk of a rate-selectable clksel clock, and a clock divisor, | ||
667 | * find the corresponding register field value. The return register value is | ||
668 | * the value before left-shifting. Returns ~0 on error | ||
669 | */ | ||
670 | u32 omap2_divisor_to_clksel(struct clk *clk, u32 div) | ||
671 | { | ||
672 | const struct clksel *clks; | ||
673 | const struct clksel_rate *clkr; | ||
674 | |||
675 | /* should never happen */ | ||
676 | WARN_ON(div == 0); | ||
677 | |||
678 | clks = omap2_get_clksel_by_parent(clk, clk->parent); | ||
679 | if (!clks) | ||
680 | return ~0; | ||
681 | |||
682 | for (clkr = clks->rates; clkr->div; clkr++) { | ||
683 | if ((clkr->flags & cpu_mask) && (clkr->div == div)) | ||
684 | break; | ||
685 | } | 315 | } |
686 | 316 | ||
687 | if (!clkr->div) { | 317 | ret = clk->ops->enable(clk); |
688 | printk(KERN_ERR "clock: Could not find divisor %d for " | 318 | if (ret) { |
689 | "clock %s parent %s\n", div, clk->name, | 319 | WARN(1, "clock: %s: could not enable: %d\n", clk->name, ret); |
690 | clk->parent->name); | 320 | goto oce_err3; |
691 | return ~0; | ||
692 | } | 321 | } |
693 | 322 | ||
694 | return clkr->val; | 323 | return 0; |
695 | } | ||
696 | |||
697 | /** | ||
698 | * omap2_clksel_get_divisor - get current divider applied to parent clock. | ||
699 | * @clk: OMAP struct clk to use. | ||
700 | * | ||
701 | * Returns the integer divisor upon success or 0 on error. | ||
702 | */ | ||
703 | u32 omap2_clksel_get_divisor(struct clk *clk) | ||
704 | { | ||
705 | u32 v; | ||
706 | |||
707 | if (!clk->clksel_mask) | ||
708 | return 0; | ||
709 | |||
710 | v = __raw_readl(clk->clksel_reg) & clk->clksel_mask; | ||
711 | v >>= __ffs(clk->clksel_mask); | ||
712 | |||
713 | return omap2_clksel_to_divisor(clk, v); | ||
714 | } | ||
715 | |||
716 | int omap2_clksel_set_rate(struct clk *clk, unsigned long rate) | ||
717 | { | ||
718 | u32 v, field_val, validrate, new_div = 0; | ||
719 | |||
720 | if (!clk->clksel_mask) | ||
721 | return -EINVAL; | ||
722 | |||
723 | validrate = omap2_clksel_round_rate_div(clk, rate, &new_div); | ||
724 | if (validrate != rate) | ||
725 | return -EINVAL; | ||
726 | |||
727 | field_val = omap2_divisor_to_clksel(clk, new_div); | ||
728 | if (field_val == ~0) | ||
729 | return -EINVAL; | ||
730 | |||
731 | v = __raw_readl(clk->clksel_reg); | ||
732 | v &= ~clk->clksel_mask; | ||
733 | v |= field_val << __ffs(clk->clksel_mask); | ||
734 | __raw_writel(v, clk->clksel_reg); | ||
735 | v = __raw_readl(clk->clksel_reg); /* OCP barrier */ | ||
736 | |||
737 | clk->rate = clk->parent->rate / new_div; | ||
738 | 324 | ||
739 | _omap2xxx_clk_commit(clk); | 325 | oce_err3: |
326 | if (clk->clkdm) | ||
327 | omap2_clkdm_clk_disable(clk->clkdm, clk); | ||
328 | oce_err2: | ||
329 | if (clk->parent) | ||
330 | omap2_clk_disable(clk->parent); | ||
331 | oce_err1: | ||
332 | clk->usecount--; | ||
740 | 333 | ||
741 | return 0; | 334 | return ret; |
742 | } | 335 | } |
743 | 336 | ||
744 | |||
745 | /* Set the clock rate for a clock source */ | 337 | /* Set the clock rate for a clock source */ |
746 | int omap2_clk_set_rate(struct clk *clk, unsigned long rate) | 338 | int omap2_clk_set_rate(struct clk *clk, unsigned long rate) |
747 | { | 339 | { |
@@ -749,11 +341,6 @@ int omap2_clk_set_rate(struct clk *clk, unsigned long rate) | |||
749 | 341 | ||
750 | pr_debug("clock: set_rate for clock %s to rate %ld\n", clk->name, rate); | 342 | pr_debug("clock: set_rate for clock %s to rate %ld\n", clk->name, rate); |
751 | 343 | ||
752 | /* CONFIG_PARTICIPANT clocks are changed only in sets via the | ||
753 | rate table mechanism, driven by mpu_speed */ | ||
754 | if (clk->flags & CONFIG_PARTICIPANT) | ||
755 | return -EINVAL; | ||
756 | |||
757 | /* dpll_ck, core_ck, virt_prcm_set; plus all clksel clocks */ | 344 | /* dpll_ck, core_ck, virt_prcm_set; plus all clksel clocks */ |
758 | if (clk->set_rate) | 345 | if (clk->set_rate) |
759 | ret = clk->set_rate(clk, rate); | 346 | ret = clk->set_rate(clk, rate); |
@@ -761,289 +348,152 @@ int omap2_clk_set_rate(struct clk *clk, unsigned long rate) | |||
761 | return ret; | 348 | return ret; |
762 | } | 349 | } |
763 | 350 | ||
764 | /* | ||
765 | * Converts encoded control register address into a full address | ||
766 | * On error, the return value (parent_div) will be 0. | ||
767 | */ | ||
768 | static u32 _omap2_clksel_get_src_field(struct clk *src_clk, struct clk *clk, | ||
769 | u32 *field_val) | ||
770 | { | ||
771 | const struct clksel *clks; | ||
772 | const struct clksel_rate *clkr; | ||
773 | |||
774 | clks = omap2_get_clksel_by_parent(clk, src_clk); | ||
775 | if (!clks) | ||
776 | return 0; | ||
777 | |||
778 | for (clkr = clks->rates; clkr->div; clkr++) { | ||
779 | if (clkr->flags & cpu_mask && clkr->flags & DEFAULT_RATE) | ||
780 | break; /* Found the default rate for this platform */ | ||
781 | } | ||
782 | |||
783 | if (!clkr->div) { | ||
784 | printk(KERN_ERR "clock: Could not find default rate for " | ||
785 | "clock %s parent %s\n", clk->name, | ||
786 | src_clk->parent->name); | ||
787 | return 0; | ||
788 | } | ||
789 | |||
790 | /* Should never happen. Add a clksel mask to the struct clk. */ | ||
791 | WARN_ON(clk->clksel_mask == 0); | ||
792 | |||
793 | *field_val = clkr->val; | ||
794 | |||
795 | return clkr->div; | ||
796 | } | ||
797 | |||
798 | int omap2_clk_set_parent(struct clk *clk, struct clk *new_parent) | 351 | int omap2_clk_set_parent(struct clk *clk, struct clk *new_parent) |
799 | { | 352 | { |
800 | u32 field_val, v, parent_div; | ||
801 | |||
802 | if (clk->flags & CONFIG_PARTICIPANT) | ||
803 | return -EINVAL; | ||
804 | |||
805 | if (!clk->clksel) | 353 | if (!clk->clksel) |
806 | return -EINVAL; | 354 | return -EINVAL; |
807 | 355 | ||
808 | parent_div = _omap2_clksel_get_src_field(new_parent, clk, &field_val); | 356 | if (clk->parent == new_parent) |
809 | if (!parent_div) | 357 | return 0; |
810 | return -EINVAL; | ||
811 | |||
812 | /* Set new source value (previous dividers if any in effect) */ | ||
813 | v = __raw_readl(clk->clksel_reg); | ||
814 | v &= ~clk->clksel_mask; | ||
815 | v |= field_val << __ffs(clk->clksel_mask); | ||
816 | __raw_writel(v, clk->clksel_reg); | ||
817 | v = __raw_readl(clk->clksel_reg); /* OCP barrier */ | ||
818 | |||
819 | _omap2xxx_clk_commit(clk); | ||
820 | |||
821 | clk_reparent(clk, new_parent); | ||
822 | |||
823 | /* CLKSEL clocks follow their parents' rates, divided by a divisor */ | ||
824 | clk->rate = new_parent->rate; | ||
825 | |||
826 | if (parent_div > 0) | ||
827 | clk->rate /= parent_div; | ||
828 | |||
829 | pr_debug("clock: set parent of %s to %s (new rate %ld)\n", | ||
830 | clk->name, clk->parent->name, clk->rate); | ||
831 | 358 | ||
832 | return 0; | 359 | return omap2_clksel_set_parent(clk, new_parent); |
833 | } | 360 | } |
834 | 361 | ||
835 | /* DPLL rate rounding code */ | 362 | /* OMAP3/4 non-CORE DPLL clkops */ |
836 | |||
837 | /** | ||
838 | * omap2_dpll_set_rate_tolerance: set the error tolerance during rate rounding | ||
839 | * @clk: struct clk * of the DPLL | ||
840 | * @tolerance: maximum rate error tolerance | ||
841 | * | ||
842 | * Set the maximum DPLL rate error tolerance for the rate rounding | ||
843 | * algorithm. The rate tolerance is an attempt to balance DPLL power | ||
844 | * saving (the least divider value "n") vs. rate fidelity (the least | ||
845 | * difference between the desired DPLL target rate and the rounded | ||
846 | * rate out of the algorithm). So, increasing the tolerance is likely | ||
847 | * to decrease DPLL power consumption and increase DPLL rate error. | ||
848 | * Returns -EINVAL if provided a null clock ptr or a clk that is not a | ||
849 | * DPLL; or 0 upon success. | ||
850 | */ | ||
851 | int omap2_dpll_set_rate_tolerance(struct clk *clk, unsigned int tolerance) | ||
852 | { | ||
853 | if (!clk || !clk->dpll_data) | ||
854 | return -EINVAL; | ||
855 | 363 | ||
856 | clk->dpll_data->rate_tolerance = tolerance; | 364 | #if defined(CONFIG_ARCH_OMAP3) || defined(CONFIG_ARCH_OMAP4) |
857 | 365 | ||
858 | return 0; | 366 | const struct clkops clkops_omap3_noncore_dpll_ops = { |
859 | } | 367 | .enable = omap3_noncore_dpll_enable, |
368 | .disable = omap3_noncore_dpll_disable, | ||
369 | }; | ||
860 | 370 | ||
861 | static unsigned long _dpll_compute_new_rate(unsigned long parent_rate, | 371 | #endif |
862 | unsigned int m, unsigned int n) | ||
863 | { | ||
864 | unsigned long long num; | ||
865 | 372 | ||
866 | num = (unsigned long long)parent_rate * m; | ||
867 | do_div(num, n); | ||
868 | return num; | ||
869 | } | ||
870 | 373 | ||
871 | /* | 374 | /* |
872 | * _dpll_test_mult - test a DPLL multiplier value | 375 | * OMAP2+ clock reset and init functions |
873 | * @m: pointer to the DPLL m (multiplier) value under test | ||
874 | * @n: current DPLL n (divider) value under test | ||
875 | * @new_rate: pointer to storage for the resulting rounded rate | ||
876 | * @target_rate: the desired DPLL rate | ||
877 | * @parent_rate: the DPLL's parent clock rate | ||
878 | * | ||
879 | * This code tests a DPLL multiplier value, ensuring that the | ||
880 | * resulting rate will not be higher than the target_rate, and that | ||
881 | * the multiplier value itself is valid for the DPLL. Initially, the | ||
882 | * integer pointed to by the m argument should be prescaled by | ||
883 | * multiplying by DPLL_SCALE_FACTOR. The code will replace this with | ||
884 | * a non-scaled m upon return. This non-scaled m will result in a | ||
885 | * new_rate as close as possible to target_rate (but not greater than | ||
886 | * target_rate) given the current (parent_rate, n, prescaled m) | ||
887 | * triple. Returns DPLL_MULT_UNDERFLOW in the event that the | ||
888 | * non-scaled m attempted to underflow, which can allow the calling | ||
889 | * function to bail out early; or 0 upon success. | ||
890 | */ | 376 | */ |
891 | static int _dpll_test_mult(int *m, int n, unsigned long *new_rate, | 377 | |
892 | unsigned long target_rate, | 378 | #ifdef CONFIG_OMAP_RESET_CLOCKS |
893 | unsigned long parent_rate) | 379 | void omap2_clk_disable_unused(struct clk *clk) |
894 | { | 380 | { |
895 | int r = 0, carry = 0; | 381 | u32 regval32, v; |
896 | 382 | ||
897 | /* Unscale m and round if necessary */ | 383 | v = (clk->flags & INVERT_ENABLE) ? (1 << clk->enable_bit) : 0; |
898 | if (*m % DPLL_SCALE_FACTOR >= DPLL_ROUNDING_VAL) | ||
899 | carry = 1; | ||
900 | *m = (*m / DPLL_SCALE_FACTOR) + carry; | ||
901 | 384 | ||
902 | /* | 385 | regval32 = __raw_readl(clk->enable_reg); |
903 | * The new rate must be <= the target rate to avoid programming | 386 | if ((regval32 & (1 << clk->enable_bit)) == v) |
904 | * a rate that is impossible for the hardware to handle | 387 | return; |
905 | */ | ||
906 | *new_rate = _dpll_compute_new_rate(parent_rate, *m, n); | ||
907 | if (*new_rate > target_rate) { | ||
908 | (*m)--; | ||
909 | *new_rate = 0; | ||
910 | } | ||
911 | 388 | ||
912 | /* Guard against m underflow */ | 389 | printk(KERN_DEBUG "Disabling unused clock \"%s\"\n", clk->name); |
913 | if (*m < DPLL_MIN_MULTIPLIER) { | 390 | if (cpu_is_omap34xx()) { |
914 | *m = DPLL_MIN_MULTIPLIER; | 391 | omap2_clk_enable(clk); |
915 | *new_rate = 0; | 392 | omap2_clk_disable(clk); |
916 | r = DPLL_MULT_UNDERFLOW; | 393 | } else { |
394 | clk->ops->disable(clk); | ||
917 | } | 395 | } |
918 | 396 | if (clk->clkdm != NULL) | |
919 | if (*new_rate == 0) | 397 | pwrdm_clkdm_state_switch(clk->clkdm); |
920 | *new_rate = _dpll_compute_new_rate(parent_rate, *m, n); | ||
921 | |||
922 | return r; | ||
923 | } | 398 | } |
399 | #endif | ||
924 | 400 | ||
925 | /** | 401 | /** |
926 | * omap2_dpll_round_rate - round a target rate for an OMAP DPLL | 402 | * omap2_clk_switch_mpurate_at_boot - switch ARM MPU rate by boot-time argument |
927 | * @clk: struct clk * for a DPLL | 403 | * @mpurate_ck_name: clk name of the clock to change rate |
928 | * @target_rate: desired DPLL clock rate | ||
929 | * | 404 | * |
930 | * Given a DPLL, a desired target rate, and a rate tolerance, round | 405 | * Change the ARM MPU clock rate to the rate specified on the command |
931 | * the target rate to a possible, programmable rate for this DPLL. | 406 | * line, if one was specified. @mpurate_ck_name should be |
932 | * Rate tolerance is assumed to be set by the caller before this | 407 | * "virt_prcm_set" on OMAP2xxx and "dpll1_ck" on OMAP34xx/OMAP36xx. |
933 | * function is called. Attempts to select the minimum possible n | 408 | * XXX Does not handle voltage scaling - on OMAP2xxx this is currently |
934 | * within the tolerance to reduce power consumption. Stores the | 409 | * handled by the virt_prcm_set clock, but this should be handled by |
935 | * computed (m, n) in the DPLL's dpll_data structure so set_rate() | 410 | * the OPP layer. XXX This is intended to be handled by the OPP layer |
936 | * will not need to call this (expensive) function again. Returns ~0 | 411 | * code in the near future and should be removed from the clock code. |
937 | * if the target rate cannot be rounded, either because the rate is | 412 | * Returns -EINVAL if 'mpurate' is zero or if clk_set_rate() rejects |
938 | * too low or because the rate tolerance is set too tightly; or the | 413 | * the rate, -ENOENT if the struct clk referred to by @mpurate_ck_name |
939 | * rounded rate upon success. | 414 | * cannot be found, or 0 upon success. |
940 | */ | 415 | */ |
941 | long omap2_dpll_round_rate(struct clk *clk, unsigned long target_rate) | 416 | int __init omap2_clk_switch_mpurate_at_boot(const char *mpurate_ck_name) |
942 | { | 417 | { |
943 | int m, n, r, e, scaled_max_m; | 418 | struct clk *mpurate_ck; |
944 | unsigned long scaled_rt_rp, new_rate; | 419 | int r; |
945 | int min_e = -1, min_e_m = -1, min_e_n = -1; | ||
946 | struct dpll_data *dd; | ||
947 | |||
948 | if (!clk || !clk->dpll_data) | ||
949 | return ~0; | ||
950 | |||
951 | dd = clk->dpll_data; | ||
952 | 420 | ||
953 | pr_debug("clock: starting DPLL round_rate for clock %s, target rate " | 421 | if (!mpurate) |
954 | "%ld\n", clk->name, target_rate); | 422 | return -EINVAL; |
955 | |||
956 | scaled_rt_rp = target_rate / (dd->clk_ref->rate / DPLL_SCALE_FACTOR); | ||
957 | scaled_max_m = dd->max_multiplier * DPLL_SCALE_FACTOR; | ||
958 | |||
959 | dd->last_rounded_rate = 0; | ||
960 | |||
961 | for (n = dd->min_divider; n <= dd->max_divider; n++) { | ||
962 | |||
963 | /* Is the (input clk, divider) pair valid for the DPLL? */ | ||
964 | r = _dpll_test_fint(clk, n); | ||
965 | if (r == DPLL_FINT_UNDERFLOW) | ||
966 | break; | ||
967 | else if (r == DPLL_FINT_INVALID) | ||
968 | continue; | ||
969 | |||
970 | /* Compute the scaled DPLL multiplier, based on the divider */ | ||
971 | m = scaled_rt_rp * n; | ||
972 | |||
973 | /* | ||
974 | * Since we're counting n up, a m overflow means we | ||
975 | * can bail out completely (since as n increases in | ||
976 | * the next iteration, there's no way that m can | ||
977 | * increase beyond the current m) | ||
978 | */ | ||
979 | if (m > scaled_max_m) | ||
980 | break; | ||
981 | |||
982 | r = _dpll_test_mult(&m, n, &new_rate, target_rate, | ||
983 | dd->clk_ref->rate); | ||
984 | |||
985 | /* m can't be set low enough for this n - try with a larger n */ | ||
986 | if (r == DPLL_MULT_UNDERFLOW) | ||
987 | continue; | ||
988 | |||
989 | e = target_rate - new_rate; | ||
990 | pr_debug("clock: n = %d: m = %d: rate error is %d " | ||
991 | "(new_rate = %ld)\n", n, m, e, new_rate); | ||
992 | |||
993 | if (min_e == -1 || | ||
994 | min_e >= (int)(abs(e) - dd->rate_tolerance)) { | ||
995 | min_e = e; | ||
996 | min_e_m = m; | ||
997 | min_e_n = n; | ||
998 | |||
999 | pr_debug("clock: found new least error %d\n", min_e); | ||
1000 | 423 | ||
1001 | /* We found good settings -- bail out now */ | 424 | mpurate_ck = clk_get(NULL, mpurate_ck_name); |
1002 | if (min_e <= dd->rate_tolerance) | 425 | if (WARN(IS_ERR(mpurate_ck), "Failed to get %s.\n", mpurate_ck_name)) |
1003 | break; | 426 | return -ENOENT; |
1004 | } | ||
1005 | } | ||
1006 | 427 | ||
1007 | if (min_e < 0) { | 428 | r = clk_set_rate(mpurate_ck, mpurate); |
1008 | pr_debug("clock: error: target rate or tolerance too low\n"); | 429 | if (IS_ERR_VALUE(r)) { |
1009 | return ~0; | 430 | WARN(1, "clock: %s: unable to set MPU rate to %d: %d\n", |
431 | mpurate_ck->name, mpurate, r); | ||
432 | return -EINVAL; | ||
1010 | } | 433 | } |
1011 | 434 | ||
1012 | dd->last_rounded_m = min_e_m; | 435 | calibrate_delay(); |
1013 | dd->last_rounded_n = min_e_n; | 436 | recalculate_root_clocks(); |
1014 | dd->last_rounded_rate = _dpll_compute_new_rate(dd->clk_ref->rate, | ||
1015 | min_e_m, min_e_n); | ||
1016 | 437 | ||
1017 | pr_debug("clock: final least error: e = %d, m = %d, n = %d\n", | 438 | clk_put(mpurate_ck); |
1018 | min_e, min_e_m, min_e_n); | ||
1019 | pr_debug("clock: final rate: %ld (target rate: %ld)\n", | ||
1020 | dd->last_rounded_rate, target_rate); | ||
1021 | 439 | ||
1022 | return dd->last_rounded_rate; | 440 | return 0; |
1023 | } | 441 | } |
1024 | 442 | ||
1025 | /*------------------------------------------------------------------------- | 443 | /** |
1026 | * Omap2 clock reset and init functions | 444 | * omap2_clk_print_new_rates - print summary of current clock tree rates |
1027 | *-------------------------------------------------------------------------*/ | 445 | * @hfclkin_ck_name: clk name for the off-chip HF oscillator |
1028 | 446 | * @core_ck_name: clk name for the on-chip CORE_CLK | |
1029 | #ifdef CONFIG_OMAP_RESET_CLOCKS | 447 | * @mpu_ck_name: clk name for the ARM MPU clock |
1030 | void omap2_clk_disable_unused(struct clk *clk) | 448 | * |
449 | * Prints a short message to the console with the HFCLKIN oscillator | ||
450 | * rate, the rate of the CORE clock, and the rate of the ARM MPU clock. | ||
451 | * Called by the boot-time MPU rate switching code. XXX This is intended | ||
452 | * to be handled by the OPP layer code in the near future and should be | ||
453 | * removed from the clock code. No return value. | ||
454 | */ | ||
455 | void __init omap2_clk_print_new_rates(const char *hfclkin_ck_name, | ||
456 | const char *core_ck_name, | ||
457 | const char *mpu_ck_name) | ||
1031 | { | 458 | { |
1032 | u32 regval32, v; | 459 | struct clk *hfclkin_ck, *core_ck, *mpu_ck; |
460 | unsigned long hfclkin_rate; | ||
1033 | 461 | ||
1034 | v = (clk->flags & INVERT_ENABLE) ? (1 << clk->enable_bit) : 0; | 462 | mpu_ck = clk_get(NULL, mpu_ck_name); |
463 | if (WARN(IS_ERR(mpu_ck), "clock: failed to get %s.\n", mpu_ck_name)) | ||
464 | return; | ||
1035 | 465 | ||
1036 | regval32 = __raw_readl(clk->enable_reg); | 466 | core_ck = clk_get(NULL, core_ck_name); |
1037 | if ((regval32 & (1 << clk->enable_bit)) == v) | 467 | if (WARN(IS_ERR(core_ck), "clock: failed to get %s.\n", core_ck_name)) |
1038 | return; | 468 | return; |
1039 | 469 | ||
1040 | printk(KERN_DEBUG "Disabling unused clock \"%s\"\n", clk->name); | 470 | hfclkin_ck = clk_get(NULL, hfclkin_ck_name); |
1041 | if (cpu_is_omap34xx()) { | 471 | if (WARN(IS_ERR(hfclkin_ck), "Failed to get %s.\n", hfclkin_ck_name)) |
1042 | omap2_clk_enable(clk); | 472 | return; |
1043 | omap2_clk_disable(clk); | 473 | |
1044 | } else | 474 | hfclkin_rate = clk_get_rate(hfclkin_ck); |
1045 | _omap2_clk_disable(clk); | 475 | |
1046 | if (clk->clkdm != NULL) | 476 | pr_info("Switched to new clocking rate (Crystal/Core/MPU): " |
1047 | pwrdm_clkdm_state_switch(clk->clkdm); | 477 | "%ld.%01ld/%ld/%ld MHz\n", |
1048 | } | 478 | (hfclkin_rate / 1000000), |
479 | ((hfclkin_rate / 100000) % 10), | ||
480 | (clk_get_rate(core_ck) / 1000000), | ||
481 | (clk_get_rate(mpu_ck) / 1000000)); | ||
482 | } | ||
483 | |||
484 | /* Common data */ | ||
485 | |||
486 | struct clk_functions omap2_clk_functions = { | ||
487 | .clk_enable = omap2_clk_enable, | ||
488 | .clk_disable = omap2_clk_disable, | ||
489 | .clk_round_rate = omap2_clk_round_rate, | ||
490 | .clk_set_rate = omap2_clk_set_rate, | ||
491 | .clk_set_parent = omap2_clk_set_parent, | ||
492 | .clk_disable_unused = omap2_clk_disable_unused, | ||
493 | #ifdef CONFIG_CPU_FREQ | ||
494 | /* These will be removed when the OPP code is integrated */ | ||
495 | .clk_init_cpufreq_table = omap2_clk_init_cpufreq_table, | ||
496 | .clk_exit_cpufreq_table = omap2_clk_exit_cpufreq_table, | ||
1049 | #endif | 497 | #endif |
498 | }; | ||
499 | |||