]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - arch/arm/cpu/arm926ejs/at91/clock.c
608af2cf72f53e6fc6b9c90a991efee41a70a819
[karo-tx-uboot.git] / arch / arm / cpu / arm926ejs / at91 / clock.c
1 /*
2  * [origin: Linux kernel linux/arch/arm/mach-at91/clock.c]
3  *
4  * Copyright (C) 2005 David Brownell
5  * Copyright (C) 2005 Ivan Kokshaysky
6  * Copyright (C) 2009 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  */
13
14 #include <common.h>
15 #include <asm/io.h>
16 #include <asm/arch/hardware.h>
17 #include <asm/arch/at91_pmc.h>
18 #include <asm/arch/clk.h>
19
20 #if !defined(CONFIG_AT91FAMILY)
21 # error You need to define CONFIG_AT91FAMILY in your board config!
22 #endif
23
24 DECLARE_GLOBAL_DATA_PTR;
25
26 unsigned long get_cpu_clk_rate(void)
27 {
28         return gd->cpu_clk_rate_hz;
29 }
30
31 unsigned long get_main_clk_rate(void)
32 {
33         return gd->main_clk_rate_hz;
34 }
35
36 unsigned long get_mck_clk_rate(void)
37 {
38         return gd->mck_rate_hz;
39 }
40
41 unsigned long get_plla_clk_rate(void)
42 {
43         return gd->plla_rate_hz;
44 }
45
46 unsigned long get_pllb_clk_rate(void)
47 {
48         return gd->pllb_rate_hz;
49 }
50
51 u32 get_pllb_init(void)
52 {
53         return gd->at91_pllb_usb_init;
54 }
55
56 static unsigned long at91_css_to_rate(unsigned long css)
57 {
58         switch (css) {
59         case AT91_PMC_MCKR_CSS_SLOW:
60                 return CONFIG_SYS_AT91_SLOW_CLOCK;
61         case AT91_PMC_MCKR_CSS_MAIN:
62                 return gd->main_clk_rate_hz;
63         case AT91_PMC_MCKR_CSS_PLLA:
64                 return gd->plla_rate_hz;
65         case AT91_PMC_MCKR_CSS_PLLB:
66                 return gd->pllb_rate_hz;
67         }
68
69         return 0;
70 }
71
72 #ifdef CONFIG_USB_ATMEL
73 static unsigned at91_pll_calc(unsigned main_freq, unsigned out_freq)
74 {
75         unsigned i, div = 0, mul = 0, diff = 1 << 30;
76         unsigned ret = (out_freq > 155000000) ? 0xbe00 : 0x3e00;
77
78         /* PLL output max 240 MHz (or 180 MHz per errata) */
79         if (out_freq > 240000000)
80                 goto fail;
81
82         for (i = 1; i < 256; i++) {
83                 int diff1;
84                 unsigned input, mul1;
85
86                 /*
87                  * PLL input between 1MHz and 32MHz per spec, but lower
88                  * frequences seem necessary in some cases so allow 100K.
89                  * Warning: some newer products need 2MHz min.
90                  */
91                 input = main_freq / i;
92 #if defined(CONFIG_AT91SAM9G20)
93                 if (input < 2000000)
94                         continue;
95 #endif
96                 if (input < 100000)
97                         continue;
98                 if (input > 32000000)
99                         continue;
100
101                 mul1 = out_freq / input;
102 #if defined(CONFIG_AT91SAM9G20)
103                 if (mul > 63)
104                         continue;
105 #endif
106                 if (mul1 > 2048)
107                         continue;
108                 if (mul1 < 2)
109                         goto fail;
110
111                 diff1 = out_freq - input * mul1;
112                 if (diff1 < 0)
113                         diff1 = -diff1;
114                 if (diff > diff1) {
115                         diff = diff1;
116                         div = i;
117                         mul = mul1;
118                         if (diff == 0)
119                                 break;
120                 }
121         }
122         if (i == 256 && diff > (out_freq >> 5))
123                 goto fail;
124         return ret | ((mul - 1) << 16) | div;
125 fail:
126         return 0;
127 }
128 #endif
129
130 static u32 at91_pll_rate(u32 freq, u32 reg)
131 {
132         unsigned mul, div;
133
134         div = reg & 0xff;
135         mul = (reg >> 16) & 0x7ff;
136         if (div && mul) {
137                 freq /= div;
138                 freq *= mul + 1;
139         } else
140                 freq = 0;
141
142         return freq;
143 }
144
145 int at91_clock_init(unsigned long main_clock)
146 {
147         unsigned freq, mckr;
148         at91_pmc_t *pmc = (at91_pmc_t *) ATMEL_BASE_PMC;
149 #ifndef CONFIG_SYS_AT91_MAIN_CLOCK
150         unsigned tmp;
151         /*
152          * When the bootloader initialized the main oscillator correctly,
153          * there's no problem using the cycle counter.  But if it didn't,
154          * or when using oscillator bypass mode, we must be told the speed
155          * of the main clock.
156          */
157         if (!main_clock) {
158                 do {
159                         tmp = readl(&pmc->mcfr);
160                 } while (!(tmp & AT91_PMC_MCFR_MAINRDY));
161                 tmp &= AT91_PMC_MCFR_MAINF_MASK;
162                 main_clock = tmp * (CONFIG_SYS_AT91_SLOW_CLOCK / 16);
163         }
164 #endif
165         gd->main_clk_rate_hz = main_clock;
166
167         /* report if PLLA is more than mildly overclocked */
168         gd->plla_rate_hz = at91_pll_rate(main_clock, readl(&pmc->pllar));
169
170 #ifdef CONFIG_USB_ATMEL
171         /*
172          * USB clock init:  choose 48 MHz PLLB value,
173          * disable 48MHz clock during usb peripheral suspend.
174          *
175          * REVISIT:  assumes MCK doesn't derive from PLLB!
176          */
177         gd->at91_pllb_usb_init = at91_pll_calc(main_clock, 48000000 * 2) |
178                              AT91_PMC_PLLBR_USBDIV_2;
179         gd->pllb_rate_hz = at91_pll_rate(main_clock, gd->at91_pllb_usb_init);
180 #endif
181
182         /*
183          * MCK and CPU derive from one of those primary clocks.
184          * For now, assume this parentage won't change.
185          */
186         mckr = readl(&pmc->mckr);
187 #if defined(CONFIG_AT91SAM9G45) || defined(CONFIG_AT91SAM9M10G45)
188         /* plla divisor by 2 */
189         gd->plla_rate_hz /= (1 << ((mckr & 1 << 12) >> 12));
190 #endif
191         gd->mck_rate_hz = at91_css_to_rate(mckr & AT91_PMC_MCKR_CSS_MASK);
192         freq = gd->mck_rate_hz;
193
194         freq /= (1 << ((mckr & AT91_PMC_MCKR_PRES_MASK) >> 2)); /* prescale */
195 #if defined(CONFIG_AT91RM9200)
196         /* mdiv */
197         gd->mck_rate_hz = freq / (1 + ((mckr & AT91_PMC_MCKR_MDIV_MASK) >> 8));
198 #elif defined(CONFIG_AT91SAM9G20)
199         /* mdiv ; (x >> 7) = ((x >> 8) * 2) */
200         gd->mck_rate_hz = (mckr & AT91_PMC_MCKR_MDIV_MASK) ?
201                 freq / ((mckr & AT91_PMC_MCKR_MDIV_MASK) >> 7) : freq;
202         if (mckr & AT91_PMC_MCKR_MDIV_MASK)
203                 freq /= 2;                      /* processor clock division */
204 #elif defined(CONFIG_AT91SAM9G45) || defined(CONFIG_AT91SAM9M10G45)
205         gd->mck_rate_hz = (mckr & AT91_PMC_MCKR_MDIV_MASK) ==
206                 (AT91_PMC_MCKR_MDIV_2 | AT91_PMC_MCKR_MDIV_4)
207                 ? freq / 3
208                 : freq / (1 << ((mckr & AT91_PMC_MCKR_MDIV_MASK) >> 8));
209 #else
210         gd->mck_rate_hz = freq / (1 << ((mckr & AT91_PMC_MCKR_MDIV_MASK) >> 8));
211 #endif
212         gd->cpu_clk_rate_hz = freq;
213
214         return 0;
215 }