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