diff options
Diffstat (limited to 'arch/arm/mach-omap2/clock34xx.c')
-rw-r--r-- | arch/arm/mach-omap2/clock34xx.c | 260 |
1 files changed, 2 insertions, 258 deletions
diff --git a/arch/arm/mach-omap2/clock34xx.c b/arch/arm/mach-omap2/clock34xx.c index 9039e8cbe487..6febd5f11e85 100644 --- a/arch/arm/mach-omap2/clock34xx.c +++ b/arch/arm/mach-omap2/clock34xx.c | |||
@@ -8,7 +8,8 @@ | |||
8 | * Jouni Högander | 8 | * Jouni Högander |
9 | * | 9 | * |
10 | * Parts of this code are based on code written by | 10 | * Parts of this code are based on code written by |
11 | * Richard Woodruff, Tony Lindgren, Tuukka Tikkanen, Karthik Dasu | 11 | * Richard Woodruff, Tony Lindgren, Tuukka Tikkanen, Karthik Dasu, |
12 | * Russell King | ||
12 | * | 13 | * |
13 | * This program is free software; you can redistribute it and/or modify | 14 | * This program is free software; you can redistribute it and/or modify |
14 | * it under the terms of the GNU General Public License version 2 as | 15 | * it under the terms of the GNU General Public License version 2 as |
@@ -17,42 +18,16 @@ | |||
17 | #undef DEBUG | 18 | #undef DEBUG |
18 | 19 | ||
19 | #include <linux/kernel.h> | 20 | #include <linux/kernel.h> |
20 | #include <linux/errno.h> | ||
21 | #include <linux/delay.h> | ||
22 | #include <linux/clk.h> | 21 | #include <linux/clk.h> |
23 | #include <linux/io.h> | 22 | #include <linux/io.h> |
24 | #include <linux/err.h> | ||
25 | 23 | ||
26 | #include <plat/cpu.h> | ||
27 | #include <plat/clock.h> | 24 | #include <plat/clock.h> |
28 | 25 | ||
29 | #include "clock.h" | 26 | #include "clock.h" |
30 | #include "clock34xx.h" | 27 | #include "clock34xx.h" |
31 | #include "prm.h" | ||
32 | #include "prm-regbits-34xx.h" | ||
33 | #include "cm.h" | 28 | #include "cm.h" |
34 | #include "cm-regbits-34xx.h" | 29 | #include "cm-regbits-34xx.h" |
35 | 30 | ||
36 | /* | ||
37 | * DPLL5_FREQ_FOR_USBHOST: USBHOST and USBTLL are the only clocks | ||
38 | * that are sourced by DPLL5, and both of these require this clock | ||
39 | * to be at 120 MHz for proper operation. | ||
40 | */ | ||
41 | #define DPLL5_FREQ_FOR_USBHOST 120000000 | ||
42 | |||
43 | /* | ||
44 | * In AM35xx IPSS, the {ICK,FCK} enable bits for modules are exported | ||
45 | * in the same register at a bit offset of 0x8. The EN_ACK for ICK is | ||
46 | * at an offset of 4 from ICK enable bit. | ||
47 | */ | ||
48 | #define AM35XX_IPSS_ICK_MASK 0xF | ||
49 | #define AM35XX_IPSS_ICK_EN_ACK_OFFSET 0x4 | ||
50 | #define AM35XX_IPSS_ICK_FCK_OFFSET 0x8 | ||
51 | #define AM35XX_IPSS_CLK_IDLEST_VAL 0 | ||
52 | |||
53 | /* needed by omap3_core_dpll_m2_set_rate() */ | ||
54 | struct clk *sdrc_ick_p, *arm_fck_p; | ||
55 | |||
56 | /** | 31 | /** |
57 | * omap3430es2_clk_ssi_find_idlest - return CM_IDLEST info for SSI | 32 | * omap3430es2_clk_ssi_find_idlest - return CM_IDLEST info for SSI |
58 | * @clk: struct clk * being enabled | 33 | * @clk: struct clk * being enabled |
@@ -149,234 +124,3 @@ const struct clkops clkops_omap3430es2_hsotgusb_wait = { | |||
149 | .find_idlest = omap3430es2_clk_hsotgusb_find_idlest, | 124 | .find_idlest = omap3430es2_clk_hsotgusb_find_idlest, |
150 | .find_companion = omap2_clk_dflt_find_companion, | 125 | .find_companion = omap2_clk_dflt_find_companion, |
151 | }; | 126 | }; |
152 | |||
153 | /** | ||
154 | * omap36xx_pwrdn_clk_enable_with_hsdiv_restore - enable clocks suffering | ||
155 | * from HSDivider PWRDN problem Implements Errata ID: i556. | ||
156 | * @clk: DPLL output struct clk | ||
157 | * | ||
158 | * 3630 only: dpll3_m3_ck, dpll4_m2_ck, dpll4_m3_ck, dpll4_m4_ck, | ||
159 | * dpll4_m5_ck & dpll4_m6_ck dividers gets loaded with reset | ||
160 | * valueafter their respective PWRDN bits are set. Any dummy write | ||
161 | * (Any other value different from the Read value) to the | ||
162 | * corresponding CM_CLKSEL register will refresh the dividers. | ||
163 | */ | ||
164 | static int omap36xx_pwrdn_clk_enable_with_hsdiv_restore(struct clk *clk) | ||
165 | { | ||
166 | u32 dummy_v, orig_v, clksel_shift; | ||
167 | int ret; | ||
168 | |||
169 | /* Clear PWRDN bit of HSDIVIDER */ | ||
170 | ret = omap2_dflt_clk_enable(clk); | ||
171 | |||
172 | /* Restore the dividers */ | ||
173 | if (!ret) { | ||
174 | clksel_shift = __ffs(clk->parent->clksel_mask); | ||
175 | orig_v = __raw_readl(clk->parent->clksel_reg); | ||
176 | dummy_v = orig_v; | ||
177 | |||
178 | /* Write any other value different from the Read value */ | ||
179 | dummy_v ^= (1 << clksel_shift); | ||
180 | __raw_writel(dummy_v, clk->parent->clksel_reg); | ||
181 | |||
182 | /* Write the original divider */ | ||
183 | __raw_writel(orig_v, clk->parent->clksel_reg); | ||
184 | } | ||
185 | |||
186 | return ret; | ||
187 | } | ||
188 | |||
189 | const struct clkops clkops_omap36xx_pwrdn_with_hsdiv_wait_restore = { | ||
190 | .enable = omap36xx_pwrdn_clk_enable_with_hsdiv_restore, | ||
191 | .disable = omap2_dflt_clk_disable, | ||
192 | .find_companion = omap2_clk_dflt_find_companion, | ||
193 | .find_idlest = omap2_clk_dflt_find_idlest, | ||
194 | }; | ||
195 | |||
196 | const struct clkops omap3_clkops_noncore_dpll_ops = { | ||
197 | .enable = omap3_noncore_dpll_enable, | ||
198 | .disable = omap3_noncore_dpll_disable, | ||
199 | }; | ||
200 | |||
201 | /** | ||
202 | * am35xx_clk_find_idlest - return clock ACK info for AM35XX IPSS | ||
203 | * @clk: struct clk * being enabled | ||
204 | * @idlest_reg: void __iomem ** to store CM_IDLEST reg address into | ||
205 | * @idlest_bit: pointer to a u8 to store the CM_IDLEST bit shift into | ||
206 | * @idlest_val: pointer to a u8 to store the CM_IDLEST indicator | ||
207 | * | ||
208 | * The interface clocks on AM35xx IPSS reflects the clock idle status | ||
209 | * in the enable register itsel at a bit offset of 4 from the enable | ||
210 | * bit. A value of 1 indicates that clock is enabled. | ||
211 | */ | ||
212 | static void am35xx_clk_find_idlest(struct clk *clk, | ||
213 | void __iomem **idlest_reg, | ||
214 | u8 *idlest_bit, | ||
215 | u8 *idlest_val) | ||
216 | { | ||
217 | *idlest_reg = (__force void __iomem *)(clk->enable_reg); | ||
218 | *idlest_bit = clk->enable_bit + AM35XX_IPSS_ICK_EN_ACK_OFFSET; | ||
219 | *idlest_val = AM35XX_IPSS_CLK_IDLEST_VAL; | ||
220 | } | ||
221 | |||
222 | /** | ||
223 | * am35xx_clk_find_companion - find companion clock to @clk | ||
224 | * @clk: struct clk * to find the companion clock of | ||
225 | * @other_reg: void __iomem ** to return the companion clock CM_*CLKEN va in | ||
226 | * @other_bit: u8 ** to return the companion clock bit shift in | ||
227 | * | ||
228 | * Some clocks don't have companion clocks. For example, modules with | ||
229 | * only an interface clock (such as HECC) don't have a companion | ||
230 | * clock. Right now, this code relies on the hardware exporting a bit | ||
231 | * in the correct companion register that indicates that the | ||
232 | * nonexistent 'companion clock' is active. Future patches will | ||
233 | * associate this type of code with per-module data structures to | ||
234 | * avoid this issue, and remove the casts. No return value. | ||
235 | */ | ||
236 | static void am35xx_clk_find_companion(struct clk *clk, void __iomem **other_reg, | ||
237 | u8 *other_bit) | ||
238 | { | ||
239 | *other_reg = (__force void __iomem *)(clk->enable_reg); | ||
240 | if (clk->enable_bit & AM35XX_IPSS_ICK_MASK) | ||
241 | *other_bit = clk->enable_bit + AM35XX_IPSS_ICK_FCK_OFFSET; | ||
242 | else | ||
243 | *other_bit = clk->enable_bit - AM35XX_IPSS_ICK_FCK_OFFSET; | ||
244 | } | ||
245 | |||
246 | const struct clkops clkops_am35xx_ipss_module_wait = { | ||
247 | .enable = omap2_dflt_clk_enable, | ||
248 | .disable = omap2_dflt_clk_disable, | ||
249 | .find_idlest = am35xx_clk_find_idlest, | ||
250 | .find_companion = am35xx_clk_find_companion, | ||
251 | }; | ||
252 | |||
253 | /** | ||
254 | * am35xx_clk_ipss_find_idlest - return CM_IDLEST info for IPSS | ||
255 | * @clk: struct clk * being enabled | ||
256 | * @idlest_reg: void __iomem ** to store CM_IDLEST reg address into | ||
257 | * @idlest_bit: pointer to a u8 to store the CM_IDLEST bit shift into | ||
258 | * @idlest_val: pointer to a u8 to store the CM_IDLEST indicator | ||
259 | * | ||
260 | * The IPSS target CM_IDLEST bit is at a different shift from the | ||
261 | * CM_{I,F}CLKEN bit. Pass back the correct info via @idlest_reg | ||
262 | * and @idlest_bit. No return value. | ||
263 | */ | ||
264 | static void am35xx_clk_ipss_find_idlest(struct clk *clk, | ||
265 | void __iomem **idlest_reg, | ||
266 | u8 *idlest_bit, | ||
267 | u8 *idlest_val) | ||
268 | { | ||
269 | u32 r; | ||
270 | |||
271 | r = (((__force u32)clk->enable_reg & ~0xf0) | 0x20); | ||
272 | *idlest_reg = (__force void __iomem *)r; | ||
273 | *idlest_bit = AM35XX_ST_IPSS_SHIFT; | ||
274 | *idlest_val = OMAP34XX_CM_IDLEST_VAL; | ||
275 | } | ||
276 | |||
277 | const struct clkops clkops_am35xx_ipss_wait = { | ||
278 | .enable = omap2_dflt_clk_enable, | ||
279 | .disable = omap2_dflt_clk_disable, | ||
280 | .find_idlest = am35xx_clk_ipss_find_idlest, | ||
281 | .find_companion = omap2_clk_dflt_find_companion, | ||
282 | }; | ||
283 | |||
284 | int omap3_dpll4_set_rate(struct clk *clk, unsigned long rate) | ||
285 | { | ||
286 | /* | ||
287 | * According to the 12-5 CDP code from TI, "Limitation 2.5" | ||
288 | * on 3430ES1 prevents us from changing DPLL multipliers or dividers | ||
289 | * on DPLL4. | ||
290 | */ | ||
291 | if (omap_rev() == OMAP3430_REV_ES1_0) { | ||
292 | printk(KERN_ERR "clock: DPLL4 cannot change rate due to " | ||
293 | "silicon 'Limitation 2.5' on 3430ES1.\n"); | ||
294 | return -EINVAL; | ||
295 | } | ||
296 | return omap3_noncore_dpll_set_rate(clk, rate); | ||
297 | } | ||
298 | |||
299 | void __init omap3_clk_lock_dpll5(void) | ||
300 | { | ||
301 | struct clk *dpll5_clk; | ||
302 | struct clk *dpll5_m2_clk; | ||
303 | |||
304 | dpll5_clk = clk_get(NULL, "dpll5_ck"); | ||
305 | clk_set_rate(dpll5_clk, DPLL5_FREQ_FOR_USBHOST); | ||
306 | clk_enable(dpll5_clk); | ||
307 | |||
308 | /* Enable autoidle to allow it to enter low power bypass */ | ||
309 | omap3_dpll_allow_idle(dpll5_clk); | ||
310 | |||
311 | /* Program dpll5_m2_clk divider for no division */ | ||
312 | dpll5_m2_clk = clk_get(NULL, "dpll5_m2_ck"); | ||
313 | clk_enable(dpll5_m2_clk); | ||
314 | clk_set_rate(dpll5_m2_clk, DPLL5_FREQ_FOR_USBHOST); | ||
315 | |||
316 | clk_disable(dpll5_m2_clk); | ||
317 | clk_disable(dpll5_clk); | ||
318 | return; | ||
319 | } | ||
320 | |||
321 | /* Common clock code */ | ||
322 | |||
323 | /* REVISIT: Move this init stuff out into clock.c */ | ||
324 | |||
325 | /* | ||
326 | * Switch the MPU rate if specified on cmdline. | ||
327 | * We cannot do this early until cmdline is parsed. | ||
328 | */ | ||
329 | static int __init omap3xxx_clk_arch_init(void) | ||
330 | { | ||
331 | struct clk *osc_sys_ck, *dpll1_ck, *arm_fck, *core_ck; | ||
332 | unsigned long osc_sys_rate; | ||
333 | bool err = 0; | ||
334 | |||
335 | if (!cpu_is_omap34xx()) | ||
336 | return 0; | ||
337 | |||
338 | if (!mpurate) | ||
339 | return -EINVAL; | ||
340 | |||
341 | /* XXX test these for success */ | ||
342 | dpll1_ck = clk_get(NULL, "dpll1_ck"); | ||
343 | if (WARN(IS_ERR(dpll1_ck), "Failed to get dpll1_ck.\n")) | ||
344 | err = 1; | ||
345 | |||
346 | arm_fck = clk_get(NULL, "arm_fck"); | ||
347 | if (WARN(IS_ERR(arm_fck), "Failed to get arm_fck.\n")) | ||
348 | err = 1; | ||
349 | |||
350 | core_ck = clk_get(NULL, "core_ck"); | ||
351 | if (WARN(IS_ERR(core_ck), "Failed to get core_ck.\n")) | ||
352 | err = 1; | ||
353 | |||
354 | osc_sys_ck = clk_get(NULL, "osc_sys_ck"); | ||
355 | if (WARN(IS_ERR(osc_sys_ck), "Failed to get osc_sys_ck.\n")) | ||
356 | err = 1; | ||
357 | |||
358 | if (err) | ||
359 | return -ENOENT; | ||
360 | |||
361 | /* REVISIT: not yet ready for 343x */ | ||
362 | if (clk_set_rate(dpll1_ck, mpurate)) | ||
363 | printk(KERN_ERR "*** Unable to set MPU rate\n"); | ||
364 | |||
365 | recalculate_root_clocks(); | ||
366 | |||
367 | osc_sys_rate = clk_get_rate(osc_sys_ck); | ||
368 | |||
369 | pr_info("Switched to new clocking rate (Crystal/Core/MPU): " | ||
370 | "%ld.%01ld/%ld/%ld MHz\n", | ||
371 | (osc_sys_rate / 1000000), | ||
372 | ((osc_sys_rate / 100000) % 10), | ||
373 | (clk_get_rate(core_ck) / 1000000), | ||
374 | (clk_get_rate(arm_fck) / 1000000)); | ||
375 | |||
376 | calibrate_delay(); | ||
377 | |||
378 | return 0; | ||
379 | } | ||
380 | arch_initcall(omap3xxx_clk_arch_init); | ||
381 | |||
382 | |||