]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blob - arch/arm/mach-omap2/clock24xx.c
[ARM] omap: introduce clock operations structure
[linux-2.6-omap-h63xx.git] / arch / arm / mach-omap2 / clock24xx.c
1 /*
2  *  linux/arch/arm/mach-omap2/clock.c
3  *
4  *  Copyright (C) 2005-2008 Texas Instruments, Inc.
5  *  Copyright (C) 2004-2008 Nokia Corporation
6  *
7  *  Contacts:
8  *  Richard Woodruff <r-woodruff2@ti.com>
9  *  Paul Walmsley
10  *
11  *  Based on earlier work by Tuukka Tikkanen, Tony Lindgren,
12  *  Gordon McNutt and RidgeRun, Inc.
13  *
14  * This program is free software; you can redistribute it and/or modify
15  * it under the terms of the GNU General Public License version 2 as
16  * published by the Free Software Foundation.
17  */
18 #undef DEBUG
19
20 #include <linux/module.h>
21 #include <linux/kernel.h>
22 #include <linux/device.h>
23 #include <linux/list.h>
24 #include <linux/errno.h>
25 #include <linux/delay.h>
26 #include <linux/clk.h>
27 #include <linux/io.h>
28 #include <linux/cpufreq.h>
29 #include <linux/bitops.h>
30
31 #include <mach/clock.h>
32 #include <mach/sram.h>
33 #include <asm/div64.h>
34
35 #include "memory.h"
36 #include "clock.h"
37 #include "prm.h"
38 #include "prm-regbits-24xx.h"
39 #include "cm.h"
40 #include "cm-regbits-24xx.h"
41
42 static const struct clkops clkops_oscck;
43 static const struct clkops clkops_fixed;
44
45 #include "clock24xx.h"
46
47 /* CM_CLKEN_PLL.EN_{54,96}M_PLL options (24XX) */
48 #define EN_APLL_STOPPED                 0
49 #define EN_APLL_LOCKED                  3
50
51 /* CM_CLKSEL1_PLL.APLLS_CLKIN options (24XX) */
52 #define APLLS_CLKIN_19_2MHZ             0
53 #define APLLS_CLKIN_13MHZ               2
54 #define APLLS_CLKIN_12MHZ               3
55
56 /* #define DOWN_VARIABLE_DPLL 1 */              /* Experimental */
57
58 static struct prcm_config *curr_prcm_set;
59 static struct clk *vclk;
60 static struct clk *sclk;
61
62 /*-------------------------------------------------------------------------
63  * Omap24xx specific clock functions
64  *-------------------------------------------------------------------------*/
65
66 /* This actually returns the rate of core_ck, not dpll_ck. */
67 static u32 omap2_get_dpll_rate_24xx(struct clk *tclk)
68 {
69         long long dpll_clk;
70         u8 amult;
71
72         dpll_clk = omap2_get_dpll_rate(tclk);
73
74         amult = cm_read_mod_reg(PLL_MOD, CM_CLKSEL2);
75         amult &= OMAP24XX_CORE_CLK_SRC_MASK;
76         dpll_clk *= amult;
77
78         return dpll_clk;
79 }
80
81 static int omap2_enable_osc_ck(struct clk *clk)
82 {
83         u32 pcc;
84
85         pcc = __raw_readl(OMAP24XX_PRCM_CLKSRC_CTRL);
86
87         __raw_writel(pcc & ~OMAP_AUTOEXTCLKMODE_MASK,
88                       OMAP24XX_PRCM_CLKSRC_CTRL);
89
90         return 0;
91 }
92
93 static void omap2_disable_osc_ck(struct clk *clk)
94 {
95         u32 pcc;
96
97         pcc = __raw_readl(OMAP24XX_PRCM_CLKSRC_CTRL);
98
99         __raw_writel(pcc | OMAP_AUTOEXTCLKMODE_MASK,
100                       OMAP24XX_PRCM_CLKSRC_CTRL);
101 }
102
103 static const struct clkops clkops_oscck = {
104         .enable         = &omap2_enable_osc_ck,
105         .disable        = &omap2_disable_osc_ck,
106 };
107
108 #ifdef OLD_CK
109 /* Recalculate SYST_CLK */
110 static void omap2_sys_clk_recalc(struct clk * clk)
111 {
112         u32 div = PRCM_CLKSRC_CTRL;
113         div &= (1 << 7) | (1 << 6);     /* Test if ext clk divided by 1 or 2 */
114         div >>= clk->rate_offset;
115         clk->rate = (clk->parent->rate / div);
116         propagate_rate(clk);
117 }
118 #endif  /* OLD_CK */
119
120 /* Enable an APLL if off */
121 static int omap2_clk_fixed_enable(struct clk *clk)
122 {
123         u32 cval, apll_mask;
124
125         apll_mask = EN_APLL_LOCKED << clk->enable_bit;
126
127         cval = cm_read_mod_reg(PLL_MOD, CM_CLKEN);
128
129         if ((cval & apll_mask) == apll_mask)
130                 return 0;   /* apll already enabled */
131
132         cval &= ~apll_mask;
133         cval |= apll_mask;
134         cm_write_mod_reg(cval, PLL_MOD, CM_CLKEN);
135
136         if (clk == &apll96_ck)
137                 cval = OMAP24XX_ST_96M_APLL;
138         else if (clk == &apll54_ck)
139                 cval = OMAP24XX_ST_54M_APLL;
140
141         omap2_wait_clock_ready(OMAP_CM_REGADDR(PLL_MOD, CM_IDLEST), cval,
142                             clk->name);
143
144         /*
145          * REVISIT: Should we return an error code if omap2_wait_clock_ready()
146          * fails?
147          */
148         return 0;
149 }
150
151 /* Stop APLL */
152 static void omap2_clk_fixed_disable(struct clk *clk)
153 {
154         u32 cval;
155
156         cval = cm_read_mod_reg(PLL_MOD, CM_CLKEN);
157         cval &= ~(EN_APLL_LOCKED << clk->enable_bit);
158         cm_write_mod_reg(cval, PLL_MOD, CM_CLKEN);
159 }
160
161 static const struct clkops clkops_fixed = {
162         .enable         = &omap2_clk_fixed_enable,
163         .disable        = &omap2_clk_fixed_disable,
164 };
165
166 /*
167  * Uses the current prcm set to tell if a rate is valid.
168  * You can go slower, but not faster within a given rate set.
169  */
170 long omap2_dpllcore_round_rate(unsigned long target_rate)
171 {
172         u32 high, low, core_clk_src;
173
174         core_clk_src = cm_read_mod_reg(PLL_MOD, CM_CLKSEL2);
175         core_clk_src &= OMAP24XX_CORE_CLK_SRC_MASK;
176
177         if (core_clk_src == CORE_CLK_SRC_DPLL) {        /* DPLL clockout */
178                 high = curr_prcm_set->dpll_speed * 2;
179                 low = curr_prcm_set->dpll_speed;
180         } else {                                /* DPLL clockout x 2 */
181                 high = curr_prcm_set->dpll_speed;
182                 low = curr_prcm_set->dpll_speed / 2;
183         }
184
185 #ifdef DOWN_VARIABLE_DPLL
186         if (target_rate > high)
187                 return high;
188         else
189                 return target_rate;
190 #else
191         if (target_rate > low)
192                 return high;
193         else
194                 return low;
195 #endif
196
197 }
198
199 static void omap2_dpllcore_recalc(struct clk *clk)
200 {
201         clk->rate = omap2_get_dpll_rate_24xx(clk);
202
203         propagate_rate(clk);
204 }
205
206 static int omap2_reprogram_dpllcore(struct clk *clk, unsigned long rate)
207 {
208         u32 cur_rate, low, mult, div, valid_rate, done_rate;
209         u32 bypass = 0;
210         struct prcm_config tmpset;
211         const struct dpll_data *dd;
212         unsigned long flags;
213         int ret = -EINVAL;
214
215         local_irq_save(flags);
216         cur_rate = omap2_get_dpll_rate_24xx(&dpll_ck);
217         mult = cm_read_mod_reg(PLL_MOD, CM_CLKSEL2);
218         mult &= OMAP24XX_CORE_CLK_SRC_MASK;
219
220         if ((rate == (cur_rate / 2)) && (mult == 2)) {
221                 omap2_reprogram_sdrc(CORE_CLK_SRC_DPLL, 1);
222         } else if ((rate == (cur_rate * 2)) && (mult == 1)) {
223                 omap2_reprogram_sdrc(CORE_CLK_SRC_DPLL_X2, 1);
224         } else if (rate != cur_rate) {
225                 valid_rate = omap2_dpllcore_round_rate(rate);
226                 if (valid_rate != rate)
227                         goto dpll_exit;
228
229                 if (mult == 1)
230                         low = curr_prcm_set->dpll_speed;
231                 else
232                         low = curr_prcm_set->dpll_speed / 2;
233
234                 dd = clk->dpll_data;
235                 if (!dd)
236                         goto dpll_exit;
237
238                 tmpset.cm_clksel1_pll = __raw_readl(dd->mult_div1_reg);
239                 tmpset.cm_clksel1_pll &= ~(dd->mult_mask |
240                                            dd->div1_mask);
241                 div = ((curr_prcm_set->xtal_speed / 1000000) - 1);
242                 tmpset.cm_clksel2_pll = cm_read_mod_reg(PLL_MOD, CM_CLKSEL2);
243                 tmpset.cm_clksel2_pll &= ~OMAP24XX_CORE_CLK_SRC_MASK;
244                 if (rate > low) {
245                         tmpset.cm_clksel2_pll |= CORE_CLK_SRC_DPLL_X2;
246                         mult = ((rate / 2) / 1000000);
247                         done_rate = CORE_CLK_SRC_DPLL_X2;
248                 } else {
249                         tmpset.cm_clksel2_pll |= CORE_CLK_SRC_DPLL;
250                         mult = (rate / 1000000);
251                         done_rate = CORE_CLK_SRC_DPLL;
252                 }
253                 tmpset.cm_clksel1_pll |= (div << __ffs(dd->mult_mask));
254                 tmpset.cm_clksel1_pll |= (mult << __ffs(dd->div1_mask));
255
256                 /* Worst case */
257                 tmpset.base_sdrc_rfr = SDRC_RFR_CTRL_BYPASS;
258
259                 if (rate == curr_prcm_set->xtal_speed)  /* If asking for 1-1 */
260                         bypass = 1;
261
262                 omap2_reprogram_sdrc(CORE_CLK_SRC_DPLL_X2, 1); /* For init_mem */
263
264                 /* Force dll lock mode */
265                 omap2_set_prcm(tmpset.cm_clksel1_pll, tmpset.base_sdrc_rfr,
266                                bypass);
267
268                 /* Errata: ret dll entry state */
269                 omap2_init_memory_params(omap2_dll_force_needed());
270                 omap2_reprogram_sdrc(done_rate, 0);
271         }
272         omap2_dpllcore_recalc(&dpll_ck);
273         ret = 0;
274
275 dpll_exit:
276         local_irq_restore(flags);
277         return(ret);
278 }
279
280 /**
281  * omap2_table_mpu_recalc - just return the MPU speed
282  * @clk: virt_prcm_set struct clk
283  *
284  * Set virt_prcm_set's rate to the mpu_speed field of the current PRCM set.
285  */
286 static void omap2_table_mpu_recalc(struct clk *clk)
287 {
288         clk->rate = curr_prcm_set->mpu_speed;
289 }
290
291 /*
292  * Look for a rate equal or less than the target rate given a configuration set.
293  *
294  * What's not entirely clear is "which" field represents the key field.
295  * Some might argue L3-DDR, others ARM, others IVA. This code is simple and
296  * just uses the ARM rates.
297  */
298 static long omap2_round_to_table_rate(struct clk *clk, unsigned long rate)
299 {
300         struct prcm_config *ptr;
301         long highest_rate;
302
303         if (clk != &virt_prcm_set)
304                 return -EINVAL;
305
306         highest_rate = -EINVAL;
307
308         for (ptr = rate_table; ptr->mpu_speed; ptr++) {
309                 if (!(ptr->flags & cpu_mask))
310                         continue;
311                 if (ptr->xtal_speed != sys_ck.rate)
312                         continue;
313
314                 highest_rate = ptr->mpu_speed;
315
316                 /* Can check only after xtal frequency check */
317                 if (ptr->mpu_speed <= rate)
318                         break;
319         }
320         return highest_rate;
321 }
322
323 /* Sets basic clocks based on the specified rate */
324 static int omap2_select_table_rate(struct clk *clk, unsigned long rate)
325 {
326         u32 cur_rate, done_rate, bypass = 0, tmp;
327         struct prcm_config *prcm;
328         unsigned long found_speed = 0;
329         unsigned long flags;
330
331         if (clk != &virt_prcm_set)
332                 return -EINVAL;
333
334         for (prcm = rate_table; prcm->mpu_speed; prcm++) {
335                 if (!(prcm->flags & cpu_mask))
336                         continue;
337
338                 if (prcm->xtal_speed != sys_ck.rate)
339                         continue;
340
341                 if (prcm->mpu_speed <= rate) {
342                         found_speed = prcm->mpu_speed;
343                         break;
344                 }
345         }
346
347         if (!found_speed) {
348                 printk(KERN_INFO "Could not set MPU rate to %luMHz\n",
349                        rate / 1000000);
350                 return -EINVAL;
351         }
352
353         curr_prcm_set = prcm;
354         cur_rate = omap2_get_dpll_rate_24xx(&dpll_ck);
355
356         if (prcm->dpll_speed == cur_rate / 2) {
357                 omap2_reprogram_sdrc(CORE_CLK_SRC_DPLL, 1);
358         } else if (prcm->dpll_speed == cur_rate * 2) {
359                 omap2_reprogram_sdrc(CORE_CLK_SRC_DPLL_X2, 1);
360         } else if (prcm->dpll_speed != cur_rate) {
361                 local_irq_save(flags);
362
363                 if (prcm->dpll_speed == prcm->xtal_speed)
364                         bypass = 1;
365
366                 if ((prcm->cm_clksel2_pll & OMAP24XX_CORE_CLK_SRC_MASK) ==
367                     CORE_CLK_SRC_DPLL_X2)
368                         done_rate = CORE_CLK_SRC_DPLL_X2;
369                 else
370                         done_rate = CORE_CLK_SRC_DPLL;
371
372                 /* MPU divider */
373                 cm_write_mod_reg(prcm->cm_clksel_mpu, MPU_MOD, CM_CLKSEL);
374
375                 /* dsp + iva1 div(2420), iva2.1(2430) */
376                 cm_write_mod_reg(prcm->cm_clksel_dsp,
377                                  OMAP24XX_DSP_MOD, CM_CLKSEL);
378
379                 cm_write_mod_reg(prcm->cm_clksel_gfx, GFX_MOD, CM_CLKSEL);
380
381                 /* Major subsystem dividers */
382                 tmp = cm_read_mod_reg(CORE_MOD, CM_CLKSEL1) & OMAP24XX_CLKSEL_DSS2_MASK;
383                 cm_write_mod_reg(prcm->cm_clksel1_core | tmp, CORE_MOD, CM_CLKSEL1);
384                 if (cpu_is_omap2430())
385                         cm_write_mod_reg(prcm->cm_clksel_mdm,
386                                          OMAP2430_MDM_MOD, CM_CLKSEL);
387
388                 /* x2 to enter init_mem */
389                 omap2_reprogram_sdrc(CORE_CLK_SRC_DPLL_X2, 1);
390
391                 omap2_set_prcm(prcm->cm_clksel1_pll, prcm->base_sdrc_rfr,
392                                bypass);
393
394                 omap2_init_memory_params(omap2_dll_force_needed());
395                 omap2_reprogram_sdrc(done_rate, 0);
396
397                 local_irq_restore(flags);
398         }
399         omap2_dpllcore_recalc(&dpll_ck);
400
401         return 0;
402 }
403
404 static struct clk_functions omap2_clk_functions = {
405         .clk_enable             = omap2_clk_enable,
406         .clk_disable            = omap2_clk_disable,
407         .clk_round_rate         = omap2_clk_round_rate,
408         .clk_set_rate           = omap2_clk_set_rate,
409         .clk_set_parent         = omap2_clk_set_parent,
410         .clk_disable_unused     = omap2_clk_disable_unused,
411 };
412
413 static u32 omap2_get_apll_clkin(void)
414 {
415         u32 aplls, sclk = 0;
416
417         aplls = cm_read_mod_reg(PLL_MOD, CM_CLKSEL1);
418         aplls &= OMAP24XX_APLLS_CLKIN_MASK;
419         aplls >>= OMAP24XX_APLLS_CLKIN_SHIFT;
420
421         if (aplls == APLLS_CLKIN_19_2MHZ)
422                 sclk = 19200000;
423         else if (aplls == APLLS_CLKIN_13MHZ)
424                 sclk = 13000000;
425         else if (aplls == APLLS_CLKIN_12MHZ)
426                 sclk = 12000000;
427
428         return sclk;
429 }
430
431 static u32 omap2_get_sysclkdiv(void)
432 {
433         u32 div;
434
435         div = __raw_readl(OMAP24XX_PRCM_CLKSRC_CTRL);
436         div &= OMAP_SYSCLKDIV_MASK;
437         div >>= OMAP_SYSCLKDIV_SHIFT;
438
439         return div;
440 }
441
442 static void omap2_osc_clk_recalc(struct clk *clk)
443 {
444         clk->rate = omap2_get_apll_clkin() * omap2_get_sysclkdiv();
445         propagate_rate(clk);
446 }
447
448 static void omap2_sys_clk_recalc(struct clk *clk)
449 {
450         clk->rate = clk->parent->rate / omap2_get_sysclkdiv();
451         propagate_rate(clk);
452 }
453
454 /*
455  * Set clocks for bypass mode for reboot to work.
456  */
457 void omap2_clk_prepare_for_reboot(void)
458 {
459         u32 rate;
460
461         if (vclk == NULL || sclk == NULL)
462                 return;
463
464         rate = clk_get_rate(sclk);
465         clk_set_rate(vclk, rate);
466 }
467
468 /*
469  * Switch the MPU rate if specified on cmdline.
470  * We cannot do this early until cmdline is parsed.
471  */
472 static int __init omap2_clk_arch_init(void)
473 {
474         if (!mpurate)
475                 return -EINVAL;
476
477         if (omap2_select_table_rate(&virt_prcm_set, mpurate))
478                 printk(KERN_ERR "Could not find matching MPU rate\n");
479
480         recalculate_root_clocks();
481
482         printk(KERN_INFO "Switched to new clocking rate (Crystal/DPLL/MPU): "
483                "%ld.%01ld/%ld/%ld MHz\n",
484                (sys_ck.rate / 1000000), (sys_ck.rate / 100000) % 10,
485                (dpll_ck.rate / 1000000), (mpu_ck.rate / 1000000)) ;
486
487         return 0;
488 }
489 arch_initcall(omap2_clk_arch_init);
490
491 int __init omap2_clk_init(void)
492 {
493         struct prcm_config *prcm;
494         struct clk **clkp;
495         u32 clkrate;
496
497         if (cpu_is_omap242x())
498                 cpu_mask = RATE_IN_242X;
499         else if (cpu_is_omap2430())
500                 cpu_mask = RATE_IN_243X;
501
502         clk_init(&omap2_clk_functions);
503
504         omap2_osc_clk_recalc(&osc_ck);
505         omap2_sys_clk_recalc(&sys_ck);
506
507         for (clkp = onchip_24xx_clks;
508              clkp < onchip_24xx_clks + ARRAY_SIZE(onchip_24xx_clks);
509              clkp++) {
510
511                 if ((*clkp)->flags & CLOCK_IN_OMAP242X && cpu_is_omap2420()) {
512                         clk_register(*clkp);
513                         continue;
514                 }
515
516                 if ((*clkp)->flags & CLOCK_IN_OMAP243X && cpu_is_omap2430()) {
517                         clk_register(*clkp);
518                         continue;
519                 }
520         }
521
522         /* Check the MPU rate set by bootloader */
523         clkrate = omap2_get_dpll_rate_24xx(&dpll_ck);
524         for (prcm = rate_table; prcm->mpu_speed; prcm++) {
525                 if (!(prcm->flags & cpu_mask))
526                         continue;
527                 if (prcm->xtal_speed != sys_ck.rate)
528                         continue;
529                 if (prcm->dpll_speed <= clkrate)
530                          break;
531         }
532         curr_prcm_set = prcm;
533
534         recalculate_root_clocks();
535
536         printk(KERN_INFO "Clocking rate (Crystal/DPLL/MPU): "
537                "%ld.%01ld/%ld/%ld MHz\n",
538                (sys_ck.rate / 1000000), (sys_ck.rate / 100000) % 10,
539                (dpll_ck.rate / 1000000), (mpu_ck.rate / 1000000)) ;
540
541         /*
542          * Only enable those clocks we will need, let the drivers
543          * enable other clocks as necessary
544          */
545         clk_enable_init_clocks();
546
547         /* Avoid sleeping sleeping during omap2_clk_prepare_for_reboot() */
548         vclk = clk_get(NULL, "virt_prcm_set");
549         sclk = clk_get(NULL, "sys_ck");
550
551         return 0;
552 }