Commit | Line | Data |
---|---|---|
d4a67d9d GJ |
1 | /* |
2 | * Atheros AR71XX/AR724X/AR913X common routines | |
3 | * | |
8889612b | 4 | * Copyright (C) 2010-2011 Jaiganesh Narayanan <jnarayanan@atheros.com> |
d4a67d9d GJ |
5 | * Copyright (C) 2011 Gabor Juhos <juhosg@openwrt.org> |
6 | * | |
8889612b GJ |
7 | * Parts of this file are based on Atheros' 2.6.15/2.6.31 BSP |
8 | * | |
d4a67d9d GJ |
9 | * This program is free software; you can redistribute it and/or modify it |
10 | * under the terms of the GNU General Public License version 2 as published | |
11 | * by the Free Software Foundation. | |
12 | */ | |
13 | ||
14 | #include <linux/kernel.h> | |
15 | #include <linux/module.h> | |
16 | #include <linux/init.h> | |
17 | #include <linux/err.h> | |
18 | #include <linux/clk.h> | |
19 | ||
20 | #include <asm/mach-ath79/ath79.h> | |
21 | #include <asm/mach-ath79/ar71xx_regs.h> | |
22 | #include "common.h" | |
23 | ||
24 | #define AR71XX_BASE_FREQ 40000000 | |
25 | #define AR724X_BASE_FREQ 5000000 | |
26 | #define AR913X_BASE_FREQ 5000000 | |
27 | ||
28 | struct clk { | |
29 | unsigned long rate; | |
30 | }; | |
31 | ||
32 | static struct clk ath79_ref_clk; | |
33 | static struct clk ath79_cpu_clk; | |
34 | static struct clk ath79_ddr_clk; | |
35 | static struct clk ath79_ahb_clk; | |
36 | static struct clk ath79_wdt_clk; | |
37 | static struct clk ath79_uart_clk; | |
38 | ||
39 | static void __init ar71xx_clocks_init(void) | |
40 | { | |
41 | u32 pll; | |
42 | u32 freq; | |
43 | u32 div; | |
44 | ||
45 | ath79_ref_clk.rate = AR71XX_BASE_FREQ; | |
46 | ||
47 | pll = ath79_pll_rr(AR71XX_PLL_REG_CPU_CONFIG); | |
48 | ||
49 | div = ((pll >> AR71XX_PLL_DIV_SHIFT) & AR71XX_PLL_DIV_MASK) + 1; | |
50 | freq = div * ath79_ref_clk.rate; | |
51 | ||
52 | div = ((pll >> AR71XX_CPU_DIV_SHIFT) & AR71XX_CPU_DIV_MASK) + 1; | |
53 | ath79_cpu_clk.rate = freq / div; | |
54 | ||
55 | div = ((pll >> AR71XX_DDR_DIV_SHIFT) & AR71XX_DDR_DIV_MASK) + 1; | |
56 | ath79_ddr_clk.rate = freq / div; | |
57 | ||
58 | div = (((pll >> AR71XX_AHB_DIV_SHIFT) & AR71XX_AHB_DIV_MASK) + 1) * 2; | |
59 | ath79_ahb_clk.rate = ath79_cpu_clk.rate / div; | |
60 | ||
61 | ath79_wdt_clk.rate = ath79_ahb_clk.rate; | |
62 | ath79_uart_clk.rate = ath79_ahb_clk.rate; | |
63 | } | |
64 | ||
65 | static void __init ar724x_clocks_init(void) | |
66 | { | |
67 | u32 pll; | |
68 | u32 freq; | |
69 | u32 div; | |
70 | ||
71 | ath79_ref_clk.rate = AR724X_BASE_FREQ; | |
72 | pll = ath79_pll_rr(AR724X_PLL_REG_CPU_CONFIG); | |
73 | ||
74 | div = ((pll >> AR724X_PLL_DIV_SHIFT) & AR724X_PLL_DIV_MASK); | |
75 | freq = div * ath79_ref_clk.rate; | |
76 | ||
77 | div = ((pll >> AR724X_PLL_REF_DIV_SHIFT) & AR724X_PLL_REF_DIV_MASK); | |
78 | freq *= div; | |
79 | ||
80 | ath79_cpu_clk.rate = freq; | |
81 | ||
82 | div = ((pll >> AR724X_DDR_DIV_SHIFT) & AR724X_DDR_DIV_MASK) + 1; | |
83 | ath79_ddr_clk.rate = freq / div; | |
84 | ||
85 | div = (((pll >> AR724X_AHB_DIV_SHIFT) & AR724X_AHB_DIV_MASK) + 1) * 2; | |
86 | ath79_ahb_clk.rate = ath79_cpu_clk.rate / div; | |
87 | ||
88 | ath79_wdt_clk.rate = ath79_ahb_clk.rate; | |
89 | ath79_uart_clk.rate = ath79_ahb_clk.rate; | |
90 | } | |
91 | ||
92 | static void __init ar913x_clocks_init(void) | |
93 | { | |
94 | u32 pll; | |
95 | u32 freq; | |
96 | u32 div; | |
97 | ||
98 | ath79_ref_clk.rate = AR913X_BASE_FREQ; | |
99 | pll = ath79_pll_rr(AR913X_PLL_REG_CPU_CONFIG); | |
100 | ||
101 | div = ((pll >> AR913X_PLL_DIV_SHIFT) & AR913X_PLL_DIV_MASK); | |
102 | freq = div * ath79_ref_clk.rate; | |
103 | ||
104 | ath79_cpu_clk.rate = freq; | |
105 | ||
106 | div = ((pll >> AR913X_DDR_DIV_SHIFT) & AR913X_DDR_DIV_MASK) + 1; | |
107 | ath79_ddr_clk.rate = freq / div; | |
108 | ||
109 | div = (((pll >> AR913X_AHB_DIV_SHIFT) & AR913X_AHB_DIV_MASK) + 1) * 2; | |
110 | ath79_ahb_clk.rate = ath79_cpu_clk.rate / div; | |
111 | ||
112 | ath79_wdt_clk.rate = ath79_ahb_clk.rate; | |
113 | ath79_uart_clk.rate = ath79_ahb_clk.rate; | |
114 | } | |
115 | ||
04225e1d GJ |
116 | static void __init ar933x_clocks_init(void) |
117 | { | |
118 | u32 clock_ctrl; | |
119 | u32 cpu_config; | |
120 | u32 freq; | |
121 | u32 t; | |
122 | ||
123 | t = ath79_reset_rr(AR933X_RESET_REG_BOOTSTRAP); | |
124 | if (t & AR933X_BOOTSTRAP_REF_CLK_40) | |
125 | ath79_ref_clk.rate = (40 * 1000 * 1000); | |
126 | else | |
127 | ath79_ref_clk.rate = (25 * 1000 * 1000); | |
128 | ||
129 | clock_ctrl = ath79_pll_rr(AR933X_PLL_CLOCK_CTRL_REG); | |
130 | if (clock_ctrl & AR933X_PLL_CLOCK_CTRL_BYPASS) { | |
131 | ath79_cpu_clk.rate = ath79_ref_clk.rate; | |
132 | ath79_ahb_clk.rate = ath79_ref_clk.rate; | |
133 | ath79_ddr_clk.rate = ath79_ref_clk.rate; | |
134 | } else { | |
135 | cpu_config = ath79_pll_rr(AR933X_PLL_CPU_CONFIG_REG); | |
136 | ||
137 | t = (cpu_config >> AR933X_PLL_CPU_CONFIG_REFDIV_SHIFT) & | |
138 | AR933X_PLL_CPU_CONFIG_REFDIV_MASK; | |
139 | freq = ath79_ref_clk.rate / t; | |
140 | ||
141 | t = (cpu_config >> AR933X_PLL_CPU_CONFIG_NINT_SHIFT) & | |
142 | AR933X_PLL_CPU_CONFIG_NINT_MASK; | |
143 | freq *= t; | |
144 | ||
145 | t = (cpu_config >> AR933X_PLL_CPU_CONFIG_OUTDIV_SHIFT) & | |
146 | AR933X_PLL_CPU_CONFIG_OUTDIV_MASK; | |
147 | if (t == 0) | |
148 | t = 1; | |
149 | ||
150 | freq >>= t; | |
151 | ||
152 | t = ((clock_ctrl >> AR933X_PLL_CLOCK_CTRL_CPU_DIV_SHIFT) & | |
153 | AR933X_PLL_CLOCK_CTRL_CPU_DIV_MASK) + 1; | |
154 | ath79_cpu_clk.rate = freq / t; | |
155 | ||
156 | t = ((clock_ctrl >> AR933X_PLL_CLOCK_CTRL_DDR_DIV_SHIFT) & | |
157 | AR933X_PLL_CLOCK_CTRL_DDR_DIV_MASK) + 1; | |
158 | ath79_ddr_clk.rate = freq / t; | |
159 | ||
160 | t = ((clock_ctrl >> AR933X_PLL_CLOCK_CTRL_AHB_DIV_SHIFT) & | |
161 | AR933X_PLL_CLOCK_CTRL_AHB_DIV_MASK) + 1; | |
162 | ath79_ahb_clk.rate = freq / t; | |
163 | } | |
164 | ||
165 | ath79_wdt_clk.rate = ath79_ref_clk.rate; | |
166 | ath79_uart_clk.rate = ath79_ref_clk.rate; | |
167 | } | |
168 | ||
8889612b GJ |
169 | static void __init ar934x_clocks_init(void) |
170 | { | |
171 | u32 pll, out_div, ref_div, nint, frac, clk_ctrl, postdiv; | |
172 | u32 cpu_pll, ddr_pll; | |
173 | u32 bootstrap; | |
174 | ||
175 | bootstrap = ath79_reset_rr(AR934X_RESET_REG_BOOTSTRAP); | |
176 | if (bootstrap & AR934X_BOOTSTRAP_REF_CLK_40) | |
177 | ath79_ref_clk.rate = 40 * 1000 * 1000; | |
178 | else | |
179 | ath79_ref_clk.rate = 25 * 1000 * 1000; | |
180 | ||
181 | pll = ath79_pll_rr(AR934X_PLL_CPU_CONFIG_REG); | |
182 | out_div = (pll >> AR934X_PLL_CPU_CONFIG_OUTDIV_SHIFT) & | |
183 | AR934X_PLL_CPU_CONFIG_OUTDIV_MASK; | |
184 | ref_div = (pll >> AR934X_PLL_CPU_CONFIG_REFDIV_SHIFT) & | |
185 | AR934X_PLL_CPU_CONFIG_REFDIV_MASK; | |
186 | nint = (pll >> AR934X_PLL_CPU_CONFIG_NINT_SHIFT) & | |
187 | AR934X_PLL_CPU_CONFIG_NINT_MASK; | |
188 | frac = (pll >> AR934X_PLL_CPU_CONFIG_NFRAC_SHIFT) & | |
189 | AR934X_PLL_CPU_CONFIG_NFRAC_MASK; | |
190 | ||
191 | cpu_pll = nint * ath79_ref_clk.rate / ref_div; | |
65fc7f99 | 192 | cpu_pll += frac * ath79_ref_clk.rate / (ref_div * (1 << 6)); |
8889612b GJ |
193 | cpu_pll /= (1 << out_div); |
194 | ||
195 | pll = ath79_pll_rr(AR934X_PLL_DDR_CONFIG_REG); | |
196 | out_div = (pll >> AR934X_PLL_DDR_CONFIG_OUTDIV_SHIFT) & | |
197 | AR934X_PLL_DDR_CONFIG_OUTDIV_MASK; | |
198 | ref_div = (pll >> AR934X_PLL_DDR_CONFIG_REFDIV_SHIFT) & | |
199 | AR934X_PLL_DDR_CONFIG_REFDIV_MASK; | |
200 | nint = (pll >> AR934X_PLL_DDR_CONFIG_NINT_SHIFT) & | |
201 | AR934X_PLL_DDR_CONFIG_NINT_MASK; | |
202 | frac = (pll >> AR934X_PLL_DDR_CONFIG_NFRAC_SHIFT) & | |
203 | AR934X_PLL_DDR_CONFIG_NFRAC_MASK; | |
204 | ||
205 | ddr_pll = nint * ath79_ref_clk.rate / ref_div; | |
65fc7f99 | 206 | ddr_pll += frac * ath79_ref_clk.rate / (ref_div * (1 << 10)); |
8889612b GJ |
207 | ddr_pll /= (1 << out_div); |
208 | ||
209 | clk_ctrl = ath79_pll_rr(AR934X_PLL_CPU_DDR_CLK_CTRL_REG); | |
210 | ||
211 | postdiv = (clk_ctrl >> AR934X_PLL_CPU_DDR_CLK_CTRL_CPU_POST_DIV_SHIFT) & | |
212 | AR934X_PLL_CPU_DDR_CLK_CTRL_CPU_POST_DIV_MASK; | |
213 | ||
214 | if (clk_ctrl & AR934X_PLL_CPU_DDR_CLK_CTRL_CPU_PLL_BYPASS) | |
215 | ath79_cpu_clk.rate = ath79_ref_clk.rate; | |
216 | else if (clk_ctrl & AR934X_PLL_CPU_DDR_CLK_CTRL_CPUCLK_FROM_CPUPLL) | |
217 | ath79_cpu_clk.rate = cpu_pll / (postdiv + 1); | |
218 | else | |
219 | ath79_cpu_clk.rate = ddr_pll / (postdiv + 1); | |
220 | ||
221 | postdiv = (clk_ctrl >> AR934X_PLL_CPU_DDR_CLK_CTRL_DDR_POST_DIV_SHIFT) & | |
222 | AR934X_PLL_CPU_DDR_CLK_CTRL_DDR_POST_DIV_MASK; | |
223 | ||
224 | if (clk_ctrl & AR934X_PLL_CPU_DDR_CLK_CTRL_DDR_PLL_BYPASS) | |
225 | ath79_ddr_clk.rate = ath79_ref_clk.rate; | |
226 | else if (clk_ctrl & AR934X_PLL_CPU_DDR_CLK_CTRL_DDRCLK_FROM_DDRPLL) | |
227 | ath79_ddr_clk.rate = ddr_pll / (postdiv + 1); | |
228 | else | |
229 | ath79_ddr_clk.rate = cpu_pll / (postdiv + 1); | |
230 | ||
231 | postdiv = (clk_ctrl >> AR934X_PLL_CPU_DDR_CLK_CTRL_AHB_POST_DIV_SHIFT) & | |
232 | AR934X_PLL_CPU_DDR_CLK_CTRL_AHB_POST_DIV_MASK; | |
233 | ||
234 | if (clk_ctrl & AR934X_PLL_CPU_DDR_CLK_CTRL_AHB_PLL_BYPASS) | |
235 | ath79_ahb_clk.rate = ath79_ref_clk.rate; | |
236 | else if (clk_ctrl & AR934X_PLL_CPU_DDR_CLK_CTRL_AHBCLK_FROM_DDRPLL) | |
237 | ath79_ahb_clk.rate = ddr_pll / (postdiv + 1); | |
238 | else | |
239 | ath79_ahb_clk.rate = cpu_pll / (postdiv + 1); | |
240 | ||
241 | ath79_wdt_clk.rate = ath79_ref_clk.rate; | |
242 | ath79_uart_clk.rate = ath79_ref_clk.rate; | |
243 | } | |
244 | ||
d4a67d9d GJ |
245 | void __init ath79_clocks_init(void) |
246 | { | |
247 | if (soc_is_ar71xx()) | |
248 | ar71xx_clocks_init(); | |
249 | else if (soc_is_ar724x()) | |
250 | ar724x_clocks_init(); | |
251 | else if (soc_is_ar913x()) | |
252 | ar913x_clocks_init(); | |
04225e1d GJ |
253 | else if (soc_is_ar933x()) |
254 | ar933x_clocks_init(); | |
8889612b GJ |
255 | else if (soc_is_ar934x()) |
256 | ar934x_clocks_init(); | |
d4a67d9d GJ |
257 | else |
258 | BUG(); | |
259 | ||
260 | pr_info("Clocks: CPU:%lu.%03luMHz, DDR:%lu.%03luMHz, AHB:%lu.%03luMHz, " | |
261 | "Ref:%lu.%03luMHz", | |
262 | ath79_cpu_clk.rate / 1000000, | |
263 | (ath79_cpu_clk.rate / 1000) % 1000, | |
264 | ath79_ddr_clk.rate / 1000000, | |
265 | (ath79_ddr_clk.rate / 1000) % 1000, | |
266 | ath79_ahb_clk.rate / 1000000, | |
267 | (ath79_ahb_clk.rate / 1000) % 1000, | |
268 | ath79_ref_clk.rate / 1000000, | |
269 | (ath79_ref_clk.rate / 1000) % 1000); | |
270 | } | |
271 | ||
272 | /* | |
273 | * Linux clock API | |
274 | */ | |
275 | struct clk *clk_get(struct device *dev, const char *id) | |
276 | { | |
277 | if (!strcmp(id, "ref")) | |
278 | return &ath79_ref_clk; | |
279 | ||
280 | if (!strcmp(id, "cpu")) | |
281 | return &ath79_cpu_clk; | |
282 | ||
283 | if (!strcmp(id, "ddr")) | |
284 | return &ath79_ddr_clk; | |
285 | ||
286 | if (!strcmp(id, "ahb")) | |
287 | return &ath79_ahb_clk; | |
288 | ||
289 | if (!strcmp(id, "wdt")) | |
290 | return &ath79_wdt_clk; | |
291 | ||
292 | if (!strcmp(id, "uart")) | |
293 | return &ath79_uart_clk; | |
294 | ||
295 | return ERR_PTR(-ENOENT); | |
296 | } | |
297 | EXPORT_SYMBOL(clk_get); | |
298 | ||
299 | int clk_enable(struct clk *clk) | |
300 | { | |
301 | return 0; | |
302 | } | |
303 | EXPORT_SYMBOL(clk_enable); | |
304 | ||
305 | void clk_disable(struct clk *clk) | |
306 | { | |
307 | } | |
308 | EXPORT_SYMBOL(clk_disable); | |
309 | ||
310 | unsigned long clk_get_rate(struct clk *clk) | |
311 | { | |
312 | return clk->rate; | |
313 | } | |
314 | EXPORT_SYMBOL(clk_get_rate); | |
315 | ||
316 | void clk_put(struct clk *clk) | |
317 | { | |
318 | } | |
319 | EXPORT_SYMBOL(clk_put); |