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