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