diff options
Diffstat (limited to 'arch/arm/plat-omap/clock.c')
-rw-r--r-- | arch/arm/plat-omap/clock.c | 1323 |
1 files changed, 1323 insertions, 0 deletions
diff --git a/arch/arm/plat-omap/clock.c b/arch/arm/plat-omap/clock.c new file mode 100644 index 000000000000..59d91b3262ba --- /dev/null +++ b/arch/arm/plat-omap/clock.c | |||
@@ -0,0 +1,1323 @@ | |||
1 | /* | ||
2 | * linux/arch/arm/plat-omap/clock.c | ||
3 | * | ||
4 | * Copyright (C) 2004 Nokia corporation | ||
5 | * Written by Tuukka Tikkanen <tuukka.tikkanen@elektrobit.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License version 2 as | ||
9 | * published by the Free Software Foundation. | ||
10 | */ | ||
11 | #include <linux/module.h> | ||
12 | #include <linux/kernel.h> | ||
13 | #include <linux/list.h> | ||
14 | #include <linux/errno.h> | ||
15 | #include <linux/err.h> | ||
16 | |||
17 | #include <asm/io.h> | ||
18 | #include <asm/semaphore.h> | ||
19 | #include <asm/hardware/clock.h> | ||
20 | #include <asm/arch/board.h> | ||
21 | #include <asm/arch/usb.h> | ||
22 | |||
23 | #include "clock.h" | ||
24 | |||
25 | static LIST_HEAD(clocks); | ||
26 | static DECLARE_MUTEX(clocks_sem); | ||
27 | static DEFINE_SPINLOCK(clockfw_lock); | ||
28 | static void propagate_rate(struct clk * clk); | ||
29 | /* UART clock function */ | ||
30 | static int set_uart_rate(struct clk * clk, unsigned long rate); | ||
31 | /* External clock (MCLK & BCLK) functions */ | ||
32 | static int set_ext_clk_rate(struct clk * clk, unsigned long rate); | ||
33 | static long round_ext_clk_rate(struct clk * clk, unsigned long rate); | ||
34 | static void init_ext_clk(struct clk * clk); | ||
35 | /* MPU virtual clock functions */ | ||
36 | static int select_table_rate(struct clk * clk, unsigned long rate); | ||
37 | static long round_to_table_rate(struct clk * clk, unsigned long rate); | ||
38 | void clk_setdpll(__u16, __u16); | ||
39 | |||
40 | static struct mpu_rate rate_table[] = { | ||
41 | /* MPU MHz, xtal MHz, dpll1 MHz, CKCTL, DPLL_CTL | ||
42 | * armdiv, dspdiv, dspmmu, tcdiv, perdiv, lcddiv | ||
43 | */ | ||
44 | #if defined(CONFIG_OMAP_ARM_216MHZ) | ||
45 | { 216000000, 12000000, 216000000, 0x050d, 0x2910 }, /* 1/1/2/2/2/8 */ | ||
46 | #endif | ||
47 | #if defined(CONFIG_OMAP_ARM_195MHZ) | ||
48 | { 195000000, 13000000, 195000000, 0x050e, 0x2790 }, /* 1/1/2/2/4/8 */ | ||
49 | #endif | ||
50 | #if defined(CONFIG_OMAP_ARM_192MHZ) | ||
51 | { 192000000, 19200000, 192000000, 0x050f, 0x2510 }, /* 1/1/2/2/8/8 */ | ||
52 | { 192000000, 12000000, 192000000, 0x050f, 0x2810 }, /* 1/1/2/2/8/8 */ | ||
53 | { 96000000, 12000000, 192000000, 0x055f, 0x2810 }, /* 2/2/2/2/8/8 */ | ||
54 | { 48000000, 12000000, 192000000, 0x0baf, 0x2810 }, /* 4/8/4/4/8/8 */ | ||
55 | { 24000000, 12000000, 192000000, 0x0fff, 0x2810 }, /* 8/8/8/8/8/8 */ | ||
56 | #endif | ||
57 | #if defined(CONFIG_OMAP_ARM_182MHZ) | ||
58 | { 182000000, 13000000, 182000000, 0x050e, 0x2710 }, /* 1/1/2/2/4/8 */ | ||
59 | #endif | ||
60 | #if defined(CONFIG_OMAP_ARM_168MHZ) | ||
61 | { 168000000, 12000000, 168000000, 0x010f, 0x2710 }, /* 1/1/1/2/8/8 */ | ||
62 | #endif | ||
63 | #if defined(CONFIG_OMAP_ARM_150MHZ) | ||
64 | { 150000000, 12000000, 150000000, 0x010a, 0x2cb0 }, /* 1/1/1/2/4/4 */ | ||
65 | #endif | ||
66 | #if defined(CONFIG_OMAP_ARM_120MHZ) | ||
67 | { 120000000, 12000000, 120000000, 0x010a, 0x2510 }, /* 1/1/1/2/4/4 */ | ||
68 | #endif | ||
69 | #if defined(CONFIG_OMAP_ARM_96MHZ) | ||
70 | { 96000000, 12000000, 96000000, 0x0005, 0x2410 }, /* 1/1/1/1/2/2 */ | ||
71 | #endif | ||
72 | #if defined(CONFIG_OMAP_ARM_60MHZ) | ||
73 | { 60000000, 12000000, 60000000, 0x0005, 0x2290 }, /* 1/1/1/1/2/2 */ | ||
74 | #endif | ||
75 | #if defined(CONFIG_OMAP_ARM_30MHZ) | ||
76 | { 30000000, 12000000, 60000000, 0x0555, 0x2290 }, /* 2/2/2/2/2/2 */ | ||
77 | #endif | ||
78 | { 0, 0, 0, 0, 0 }, | ||
79 | }; | ||
80 | |||
81 | |||
82 | static void ckctl_recalc(struct clk * clk); | ||
83 | int __clk_enable(struct clk *clk); | ||
84 | void __clk_disable(struct clk *clk); | ||
85 | void __clk_unuse(struct clk *clk); | ||
86 | int __clk_use(struct clk *clk); | ||
87 | |||
88 | |||
89 | static void followparent_recalc(struct clk * clk) | ||
90 | { | ||
91 | clk->rate = clk->parent->rate; | ||
92 | } | ||
93 | |||
94 | |||
95 | static void watchdog_recalc(struct clk * clk) | ||
96 | { | ||
97 | clk->rate = clk->parent->rate / 14; | ||
98 | } | ||
99 | |||
100 | static void uart_recalc(struct clk * clk) | ||
101 | { | ||
102 | unsigned int val = omap_readl(clk->enable_reg); | ||
103 | if (val & clk->enable_bit) | ||
104 | clk->rate = 48000000; | ||
105 | else | ||
106 | clk->rate = 12000000; | ||
107 | } | ||
108 | |||
109 | static struct clk ck_ref = { | ||
110 | .name = "ck_ref", | ||
111 | .rate = 12000000, | ||
112 | .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | | ||
113 | ALWAYS_ENABLED, | ||
114 | }; | ||
115 | |||
116 | static struct clk ck_dpll1 = { | ||
117 | .name = "ck_dpll1", | ||
118 | .parent = &ck_ref, | ||
119 | .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | | ||
120 | RATE_PROPAGATES | ALWAYS_ENABLED, | ||
121 | }; | ||
122 | |||
123 | static struct clk ck_dpll1out = { | ||
124 | .name = "ck_dpll1out", | ||
125 | .parent = &ck_dpll1, | ||
126 | .flags = CLOCK_IN_OMAP16XX, | ||
127 | .enable_reg = ARM_IDLECT2, | ||
128 | .enable_bit = EN_CKOUT_ARM, | ||
129 | .recalc = &followparent_recalc, | ||
130 | }; | ||
131 | |||
132 | static struct clk arm_ck = { | ||
133 | .name = "arm_ck", | ||
134 | .parent = &ck_dpll1, | ||
135 | .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | | ||
136 | RATE_CKCTL | RATE_PROPAGATES | ALWAYS_ENABLED, | ||
137 | .rate_offset = CKCTL_ARMDIV_OFFSET, | ||
138 | .recalc = &ckctl_recalc, | ||
139 | }; | ||
140 | |||
141 | static struct clk armper_ck = { | ||
142 | .name = "armper_ck", | ||
143 | .parent = &ck_dpll1, | ||
144 | .flags = CLOCK_IN_OMAP730 | CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | | ||
145 | RATE_CKCTL, | ||
146 | .enable_reg = ARM_IDLECT2, | ||
147 | .enable_bit = EN_PERCK, | ||
148 | .rate_offset = CKCTL_PERDIV_OFFSET, | ||
149 | .recalc = &ckctl_recalc, | ||
150 | }; | ||
151 | |||
152 | static struct clk arm_gpio_ck = { | ||
153 | .name = "arm_gpio_ck", | ||
154 | .parent = &ck_dpll1, | ||
155 | .flags = CLOCK_IN_OMAP1510, | ||
156 | .enable_reg = ARM_IDLECT2, | ||
157 | .enable_bit = EN_GPIOCK, | ||
158 | .recalc = &followparent_recalc, | ||
159 | }; | ||
160 | |||
161 | static struct clk armxor_ck = { | ||
162 | .name = "armxor_ck", | ||
163 | .parent = &ck_ref, | ||
164 | .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX, | ||
165 | .enable_reg = ARM_IDLECT2, | ||
166 | .enable_bit = EN_XORPCK, | ||
167 | .recalc = &followparent_recalc, | ||
168 | }; | ||
169 | |||
170 | static struct clk armtim_ck = { | ||
171 | .name = "armtim_ck", | ||
172 | .parent = &ck_ref, | ||
173 | .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX, | ||
174 | .enable_reg = ARM_IDLECT2, | ||
175 | .enable_bit = EN_TIMCK, | ||
176 | .recalc = &followparent_recalc, | ||
177 | }; | ||
178 | |||
179 | static struct clk armwdt_ck = { | ||
180 | .name = "armwdt_ck", | ||
181 | .parent = &ck_ref, | ||
182 | .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX, | ||
183 | .enable_reg = ARM_IDLECT2, | ||
184 | .enable_bit = EN_WDTCK, | ||
185 | .recalc = &watchdog_recalc, | ||
186 | }; | ||
187 | |||
188 | static struct clk arminth_ck16xx = { | ||
189 | .name = "arminth_ck", | ||
190 | .parent = &arm_ck, | ||
191 | .flags = CLOCK_IN_OMAP16XX | ALWAYS_ENABLED, | ||
192 | .recalc = &followparent_recalc, | ||
193 | /* Note: On 16xx the frequency can be divided by 2 by programming | ||
194 | * ARM_CKCTL:ARM_INTHCK_SEL(14) to 1 | ||
195 | * | ||
196 | * 1510 version is in TC clocks. | ||
197 | */ | ||
198 | }; | ||
199 | |||
200 | static struct clk dsp_ck = { | ||
201 | .name = "dsp_ck", | ||
202 | .parent = &ck_dpll1, | ||
203 | .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | | ||
204 | RATE_CKCTL, | ||
205 | .enable_reg = ARM_CKCTL, | ||
206 | .enable_bit = EN_DSPCK, | ||
207 | .rate_offset = CKCTL_DSPDIV_OFFSET, | ||
208 | .recalc = &ckctl_recalc, | ||
209 | }; | ||
210 | |||
211 | static struct clk dspmmu_ck = { | ||
212 | .name = "dspmmu_ck", | ||
213 | .parent = &ck_dpll1, | ||
214 | .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | | ||
215 | RATE_CKCTL | ALWAYS_ENABLED, | ||
216 | .rate_offset = CKCTL_DSPMMUDIV_OFFSET, | ||
217 | .recalc = &ckctl_recalc, | ||
218 | }; | ||
219 | |||
220 | static struct clk dspper_ck = { | ||
221 | .name = "dspper_ck", | ||
222 | .parent = &ck_dpll1, | ||
223 | .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | | ||
224 | RATE_CKCTL | DSP_DOMAIN_CLOCK | VIRTUAL_IO_ADDRESS, | ||
225 | .enable_reg = DSP_IDLECT2, | ||
226 | .enable_bit = EN_PERCK, | ||
227 | .rate_offset = CKCTL_PERDIV_OFFSET, | ||
228 | .recalc = &followparent_recalc, | ||
229 | //.recalc = &ckctl_recalc, | ||
230 | }; | ||
231 | |||
232 | static struct clk dspxor_ck = { | ||
233 | .name = "dspxor_ck", | ||
234 | .parent = &ck_ref, | ||
235 | .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | | ||
236 | DSP_DOMAIN_CLOCK | VIRTUAL_IO_ADDRESS, | ||
237 | .enable_reg = DSP_IDLECT2, | ||
238 | .enable_bit = EN_XORPCK, | ||
239 | .recalc = &followparent_recalc, | ||
240 | }; | ||
241 | |||
242 | static struct clk dsptim_ck = { | ||
243 | .name = "dsptim_ck", | ||
244 | .parent = &ck_ref, | ||
245 | .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | | ||
246 | DSP_DOMAIN_CLOCK | VIRTUAL_IO_ADDRESS, | ||
247 | .enable_reg = DSP_IDLECT2, | ||
248 | .enable_bit = EN_DSPTIMCK, | ||
249 | .recalc = &followparent_recalc, | ||
250 | }; | ||
251 | |||
252 | static struct clk tc_ck = { | ||
253 | .name = "tc_ck", | ||
254 | .parent = &ck_dpll1, | ||
255 | .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP730 | | ||
256 | RATE_CKCTL | RATE_PROPAGATES | ALWAYS_ENABLED, | ||
257 | .rate_offset = CKCTL_TCDIV_OFFSET, | ||
258 | .recalc = &ckctl_recalc, | ||
259 | }; | ||
260 | |||
261 | static struct clk arminth_ck1510 = { | ||
262 | .name = "arminth_ck", | ||
263 | .parent = &tc_ck, | ||
264 | .flags = CLOCK_IN_OMAP1510 | ALWAYS_ENABLED, | ||
265 | .recalc = &followparent_recalc, | ||
266 | /* Note: On 1510 the frequency follows TC_CK | ||
267 | * | ||
268 | * 16xx version is in MPU clocks. | ||
269 | */ | ||
270 | }; | ||
271 | |||
272 | static struct clk tipb_ck = { | ||
273 | .name = "tibp_ck", | ||
274 | .parent = &tc_ck, | ||
275 | .flags = CLOCK_IN_OMAP1510 | ALWAYS_ENABLED, | ||
276 | .recalc = &followparent_recalc, | ||
277 | }; | ||
278 | |||
279 | static struct clk l3_ocpi_ck = { | ||
280 | .name = "l3_ocpi_ck", | ||
281 | .parent = &tc_ck, | ||
282 | .flags = CLOCK_IN_OMAP16XX, | ||
283 | .enable_reg = ARM_IDLECT3, | ||
284 | .enable_bit = EN_OCPI_CK, | ||
285 | .recalc = &followparent_recalc, | ||
286 | }; | ||
287 | |||
288 | static struct clk tc1_ck = { | ||
289 | .name = "tc1_ck", | ||
290 | .parent = &tc_ck, | ||
291 | .flags = CLOCK_IN_OMAP16XX, | ||
292 | .enable_reg = ARM_IDLECT3, | ||
293 | .enable_bit = EN_TC1_CK, | ||
294 | .recalc = &followparent_recalc, | ||
295 | }; | ||
296 | |||
297 | static struct clk tc2_ck = { | ||
298 | .name = "tc2_ck", | ||
299 | .parent = &tc_ck, | ||
300 | .flags = CLOCK_IN_OMAP16XX, | ||
301 | .enable_reg = ARM_IDLECT3, | ||
302 | .enable_bit = EN_TC2_CK, | ||
303 | .recalc = &followparent_recalc, | ||
304 | }; | ||
305 | |||
306 | static struct clk dma_ck = { | ||
307 | .name = "dma_ck", | ||
308 | .parent = &tc_ck, | ||
309 | .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | | ||
310 | ALWAYS_ENABLED, | ||
311 | .recalc = &followparent_recalc, | ||
312 | }; | ||
313 | |||
314 | static struct clk dma_lcdfree_ck = { | ||
315 | .name = "dma_lcdfree_ck", | ||
316 | .parent = &tc_ck, | ||
317 | .flags = CLOCK_IN_OMAP16XX | ALWAYS_ENABLED, | ||
318 | .recalc = &followparent_recalc, | ||
319 | }; | ||
320 | |||
321 | static struct clk api_ck = { | ||
322 | .name = "api_ck", | ||
323 | .parent = &tc_ck, | ||
324 | .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX, | ||
325 | .enable_reg = ARM_IDLECT2, | ||
326 | .enable_bit = EN_APICK, | ||
327 | .recalc = &followparent_recalc, | ||
328 | }; | ||
329 | |||
330 | static struct clk lb_ck = { | ||
331 | .name = "lb_ck", | ||
332 | .parent = &tc_ck, | ||
333 | .flags = CLOCK_IN_OMAP1510, | ||
334 | .enable_reg = ARM_IDLECT2, | ||
335 | .enable_bit = EN_LBCK, | ||
336 | .recalc = &followparent_recalc, | ||
337 | }; | ||
338 | |||
339 | static struct clk rhea1_ck = { | ||
340 | .name = "rhea1_ck", | ||
341 | .parent = &tc_ck, | ||
342 | .flags = CLOCK_IN_OMAP16XX | ALWAYS_ENABLED, | ||
343 | .recalc = &followparent_recalc, | ||
344 | }; | ||
345 | |||
346 | static struct clk rhea2_ck = { | ||
347 | .name = "rhea2_ck", | ||
348 | .parent = &tc_ck, | ||
349 | .flags = CLOCK_IN_OMAP16XX | ALWAYS_ENABLED, | ||
350 | .recalc = &followparent_recalc, | ||
351 | }; | ||
352 | |||
353 | static struct clk lcd_ck = { | ||
354 | .name = "lcd_ck", | ||
355 | .parent = &ck_dpll1, | ||
356 | .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP730 | | ||
357 | RATE_CKCTL, | ||
358 | .enable_reg = ARM_IDLECT2, | ||
359 | .enable_bit = EN_LCDCK, | ||
360 | .rate_offset = CKCTL_LCDDIV_OFFSET, | ||
361 | .recalc = &ckctl_recalc, | ||
362 | }; | ||
363 | |||
364 | static struct clk uart1_1510 = { | ||
365 | .name = "uart1_ck", | ||
366 | /* Direct from ULPD, no parent */ | ||
367 | .rate = 12000000, | ||
368 | .flags = CLOCK_IN_OMAP1510 | ENABLE_REG_32BIT | ALWAYS_ENABLED, | ||
369 | .enable_reg = MOD_CONF_CTRL_0, | ||
370 | .enable_bit = 29, /* Chooses between 12MHz and 48MHz */ | ||
371 | .set_rate = &set_uart_rate, | ||
372 | .recalc = &uart_recalc, | ||
373 | }; | ||
374 | |||
375 | static struct clk uart1_16xx = { | ||
376 | .name = "uart1_ck", | ||
377 | /* Direct from ULPD, no parent */ | ||
378 | .rate = 48000000, | ||
379 | .flags = CLOCK_IN_OMAP16XX | RATE_FIXED | ENABLE_REG_32BIT, | ||
380 | .enable_reg = MOD_CONF_CTRL_0, | ||
381 | .enable_bit = 29, | ||
382 | }; | ||
383 | |||
384 | static struct clk uart2_ck = { | ||
385 | .name = "uart2_ck", | ||
386 | /* Direct from ULPD, no parent */ | ||
387 | .rate = 12000000, | ||
388 | .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | ENABLE_REG_32BIT, | ||
389 | .enable_reg = MOD_CONF_CTRL_0, | ||
390 | .enable_bit = 30, /* Chooses between 12MHz and 48MHz */ | ||
391 | .set_rate = &set_uart_rate, | ||
392 | .recalc = &uart_recalc, | ||
393 | }; | ||
394 | |||
395 | static struct clk uart3_1510 = { | ||
396 | .name = "uart3_ck", | ||
397 | /* Direct from ULPD, no parent */ | ||
398 | .rate = 12000000, | ||
399 | .flags = CLOCK_IN_OMAP1510 | ENABLE_REG_32BIT | ALWAYS_ENABLED, | ||
400 | .enable_reg = MOD_CONF_CTRL_0, | ||
401 | .enable_bit = 31, /* Chooses between 12MHz and 48MHz */ | ||
402 | .set_rate = &set_uart_rate, | ||
403 | .recalc = &uart_recalc, | ||
404 | }; | ||
405 | |||
406 | static struct clk uart3_16xx = { | ||
407 | .name = "uart3_ck", | ||
408 | /* Direct from ULPD, no parent */ | ||
409 | .rate = 48000000, | ||
410 | .flags = CLOCK_IN_OMAP16XX | RATE_FIXED | ENABLE_REG_32BIT, | ||
411 | .enable_reg = MOD_CONF_CTRL_0, | ||
412 | .enable_bit = 31, | ||
413 | }; | ||
414 | |||
415 | static struct clk usb_clko = { /* 6 MHz output on W4_USB_CLKO */ | ||
416 | .name = "usb_clko", | ||
417 | /* Direct from ULPD, no parent */ | ||
418 | .rate = 6000000, | ||
419 | .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | | ||
420 | RATE_FIXED | ENABLE_REG_32BIT, | ||
421 | .enable_reg = ULPD_CLOCK_CTRL, | ||
422 | .enable_bit = USB_MCLK_EN_BIT, | ||
423 | }; | ||
424 | |||
425 | static struct clk usb_hhc_ck1510 = { | ||
426 | .name = "usb_hhc_ck", | ||
427 | /* Direct from ULPD, no parent */ | ||
428 | .rate = 48000000, /* Actually 2 clocks, 12MHz and 48MHz */ | ||
429 | .flags = CLOCK_IN_OMAP1510 | | ||
430 | RATE_FIXED | ENABLE_REG_32BIT, | ||
431 | .enable_reg = MOD_CONF_CTRL_0, | ||
432 | .enable_bit = USB_HOST_HHC_UHOST_EN, | ||
433 | }; | ||
434 | |||
435 | static struct clk usb_hhc_ck16xx = { | ||
436 | .name = "usb_hhc_ck", | ||
437 | /* Direct from ULPD, no parent */ | ||
438 | .rate = 48000000, | ||
439 | /* OTG_SYSCON_2.OTG_PADEN == 0 (not 1510-compatible) */ | ||
440 | .flags = CLOCK_IN_OMAP16XX | | ||
441 | RATE_FIXED | ENABLE_REG_32BIT, | ||
442 | .enable_reg = OTG_BASE + 0x08 /* OTG_SYSCON_2 */, | ||
443 | .enable_bit = 8 /* UHOST_EN */, | ||
444 | }; | ||
445 | |||
446 | static struct clk mclk_1510 = { | ||
447 | .name = "mclk", | ||
448 | /* Direct from ULPD, no parent. May be enabled by ext hardware. */ | ||
449 | .rate = 12000000, | ||
450 | .flags = CLOCK_IN_OMAP1510 | RATE_FIXED, | ||
451 | }; | ||
452 | |||
453 | static struct clk mclk_16xx = { | ||
454 | .name = "mclk", | ||
455 | /* Direct from ULPD, no parent. May be enabled by ext hardware. */ | ||
456 | .flags = CLOCK_IN_OMAP16XX, | ||
457 | .enable_reg = COM_CLK_DIV_CTRL_SEL, | ||
458 | .enable_bit = COM_ULPD_PLL_CLK_REQ, | ||
459 | .set_rate = &set_ext_clk_rate, | ||
460 | .round_rate = &round_ext_clk_rate, | ||
461 | .init = &init_ext_clk, | ||
462 | }; | ||
463 | |||
464 | static struct clk bclk_1510 = { | ||
465 | .name = "bclk", | ||
466 | /* Direct from ULPD, no parent. May be enabled by ext hardware. */ | ||
467 | .rate = 12000000, | ||
468 | .flags = CLOCK_IN_OMAP1510 | RATE_FIXED, | ||
469 | }; | ||
470 | |||
471 | static struct clk bclk_16xx = { | ||
472 | .name = "bclk", | ||
473 | /* Direct from ULPD, no parent. May be enabled by ext hardware. */ | ||
474 | .flags = CLOCK_IN_OMAP16XX, | ||
475 | .enable_reg = SWD_CLK_DIV_CTRL_SEL, | ||
476 | .enable_bit = SWD_ULPD_PLL_CLK_REQ, | ||
477 | .set_rate = &set_ext_clk_rate, | ||
478 | .round_rate = &round_ext_clk_rate, | ||
479 | .init = &init_ext_clk, | ||
480 | }; | ||
481 | |||
482 | static struct clk mmc1_ck = { | ||
483 | .name = "mmc1_ck", | ||
484 | /* Functional clock is direct from ULPD, interface clock is ARMPER */ | ||
485 | .parent = &armper_ck, | ||
486 | .rate = 48000000, | ||
487 | .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | | ||
488 | RATE_FIXED | ENABLE_REG_32BIT, | ||
489 | .enable_reg = MOD_CONF_CTRL_0, | ||
490 | .enable_bit = 23, | ||
491 | }; | ||
492 | |||
493 | static struct clk mmc2_ck = { | ||
494 | .name = "mmc2_ck", | ||
495 | /* Functional clock is direct from ULPD, interface clock is ARMPER */ | ||
496 | .parent = &armper_ck, | ||
497 | .rate = 48000000, | ||
498 | .flags = CLOCK_IN_OMAP16XX | | ||
499 | RATE_FIXED | ENABLE_REG_32BIT, | ||
500 | .enable_reg = MOD_CONF_CTRL_0, | ||
501 | .enable_bit = 20, | ||
502 | }; | ||
503 | |||
504 | static struct clk virtual_ck_mpu = { | ||
505 | .name = "mpu", | ||
506 | .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | | ||
507 | VIRTUAL_CLOCK | ALWAYS_ENABLED, | ||
508 | .parent = &arm_ck, /* Is smarter alias for */ | ||
509 | .recalc = &followparent_recalc, | ||
510 | .set_rate = &select_table_rate, | ||
511 | .round_rate = &round_to_table_rate, | ||
512 | }; | ||
513 | |||
514 | |||
515 | static struct clk * onchip_clks[] = { | ||
516 | /* non-ULPD clocks */ | ||
517 | &ck_ref, | ||
518 | &ck_dpll1, | ||
519 | /* CK_GEN1 clocks */ | ||
520 | &ck_dpll1out, | ||
521 | &arm_ck, | ||
522 | &armper_ck, | ||
523 | &arm_gpio_ck, | ||
524 | &armxor_ck, | ||
525 | &armtim_ck, | ||
526 | &armwdt_ck, | ||
527 | &arminth_ck1510, &arminth_ck16xx, | ||
528 | /* CK_GEN2 clocks */ | ||
529 | &dsp_ck, | ||
530 | &dspmmu_ck, | ||
531 | &dspper_ck, | ||
532 | &dspxor_ck, | ||
533 | &dsptim_ck, | ||
534 | /* CK_GEN3 clocks */ | ||
535 | &tc_ck, | ||
536 | &tipb_ck, | ||
537 | &l3_ocpi_ck, | ||
538 | &tc1_ck, | ||
539 | &tc2_ck, | ||
540 | &dma_ck, | ||
541 | &dma_lcdfree_ck, | ||
542 | &api_ck, | ||
543 | &lb_ck, | ||
544 | &rhea1_ck, | ||
545 | &rhea2_ck, | ||
546 | &lcd_ck, | ||
547 | /* ULPD clocks */ | ||
548 | &uart1_1510, | ||
549 | &uart1_16xx, | ||
550 | &uart2_ck, | ||
551 | &uart3_1510, | ||
552 | &uart3_16xx, | ||
553 | &usb_clko, | ||
554 | &usb_hhc_ck1510, &usb_hhc_ck16xx, | ||
555 | &mclk_1510, &mclk_16xx, | ||
556 | &bclk_1510, &bclk_16xx, | ||
557 | &mmc1_ck, | ||
558 | &mmc2_ck, | ||
559 | /* Virtual clocks */ | ||
560 | &virtual_ck_mpu, | ||
561 | }; | ||
562 | |||
563 | struct clk *clk_get(struct device *dev, const char *id) | ||
564 | { | ||
565 | struct clk *p, *clk = ERR_PTR(-ENOENT); | ||
566 | |||
567 | down(&clocks_sem); | ||
568 | list_for_each_entry(p, &clocks, node) { | ||
569 | if (strcmp(id, p->name) == 0 && try_module_get(p->owner)) { | ||
570 | clk = p; | ||
571 | break; | ||
572 | } | ||
573 | } | ||
574 | up(&clocks_sem); | ||
575 | |||
576 | return clk; | ||
577 | } | ||
578 | EXPORT_SYMBOL(clk_get); | ||
579 | |||
580 | |||
581 | void clk_put(struct clk *clk) | ||
582 | { | ||
583 | if (clk && !IS_ERR(clk)) | ||
584 | module_put(clk->owner); | ||
585 | } | ||
586 | EXPORT_SYMBOL(clk_put); | ||
587 | |||
588 | |||
589 | int __clk_enable(struct clk *clk) | ||
590 | { | ||
591 | __u16 regval16; | ||
592 | __u32 regval32; | ||
593 | |||
594 | if (clk->flags & ALWAYS_ENABLED) | ||
595 | return 0; | ||
596 | |||
597 | if (unlikely(clk->enable_reg == 0)) { | ||
598 | printk(KERN_ERR "clock.c: Enable for %s without enable code\n", | ||
599 | clk->name); | ||
600 | return 0; | ||
601 | } | ||
602 | |||
603 | if (clk->flags & DSP_DOMAIN_CLOCK) { | ||
604 | __clk_use(&api_ck); | ||
605 | } | ||
606 | |||
607 | if (clk->flags & ENABLE_REG_32BIT) { | ||
608 | if (clk->flags & VIRTUAL_IO_ADDRESS) { | ||
609 | regval32 = __raw_readl(clk->enable_reg); | ||
610 | regval32 |= (1 << clk->enable_bit); | ||
611 | __raw_writel(regval32, clk->enable_reg); | ||
612 | } else { | ||
613 | regval32 = omap_readl(clk->enable_reg); | ||
614 | regval32 |= (1 << clk->enable_bit); | ||
615 | omap_writel(regval32, clk->enable_reg); | ||
616 | } | ||
617 | } else { | ||
618 | if (clk->flags & VIRTUAL_IO_ADDRESS) { | ||
619 | regval16 = __raw_readw(clk->enable_reg); | ||
620 | regval16 |= (1 << clk->enable_bit); | ||
621 | __raw_writew(regval16, clk->enable_reg); | ||
622 | } else { | ||
623 | regval16 = omap_readw(clk->enable_reg); | ||
624 | regval16 |= (1 << clk->enable_bit); | ||
625 | omap_writew(regval16, clk->enable_reg); | ||
626 | } | ||
627 | } | ||
628 | |||
629 | if (clk->flags & DSP_DOMAIN_CLOCK) { | ||
630 | __clk_unuse(&api_ck); | ||
631 | } | ||
632 | |||
633 | return 0; | ||
634 | } | ||
635 | |||
636 | |||
637 | void __clk_disable(struct clk *clk) | ||
638 | { | ||
639 | __u16 regval16; | ||
640 | __u32 regval32; | ||
641 | |||
642 | if (clk->enable_reg == 0) | ||
643 | return; | ||
644 | |||
645 | if (clk->flags & DSP_DOMAIN_CLOCK) { | ||
646 | __clk_use(&api_ck); | ||
647 | } | ||
648 | |||
649 | if (clk->flags & ENABLE_REG_32BIT) { | ||
650 | if (clk->flags & VIRTUAL_IO_ADDRESS) { | ||
651 | regval32 = __raw_readl(clk->enable_reg); | ||
652 | regval32 &= ~(1 << clk->enable_bit); | ||
653 | __raw_writel(regval32, clk->enable_reg); | ||
654 | } else { | ||
655 | regval32 = omap_readl(clk->enable_reg); | ||
656 | regval32 &= ~(1 << clk->enable_bit); | ||
657 | omap_writel(regval32, clk->enable_reg); | ||
658 | } | ||
659 | } else { | ||
660 | if (clk->flags & VIRTUAL_IO_ADDRESS) { | ||
661 | regval16 = __raw_readw(clk->enable_reg); | ||
662 | regval16 &= ~(1 << clk->enable_bit); | ||
663 | __raw_writew(regval16, clk->enable_reg); | ||
664 | } else { | ||
665 | regval16 = omap_readw(clk->enable_reg); | ||
666 | regval16 &= ~(1 << clk->enable_bit); | ||
667 | omap_writew(regval16, clk->enable_reg); | ||
668 | } | ||
669 | } | ||
670 | |||
671 | if (clk->flags & DSP_DOMAIN_CLOCK) { | ||
672 | __clk_unuse(&api_ck); | ||
673 | } | ||
674 | } | ||
675 | |||
676 | |||
677 | void __clk_unuse(struct clk *clk) | ||
678 | { | ||
679 | if (clk->usecount > 0 && !(--clk->usecount)) { | ||
680 | __clk_disable(clk); | ||
681 | if (likely(clk->parent)) | ||
682 | __clk_unuse(clk->parent); | ||
683 | } | ||
684 | } | ||
685 | |||
686 | |||
687 | int __clk_use(struct clk *clk) | ||
688 | { | ||
689 | int ret = 0; | ||
690 | if (clk->usecount++ == 0) { | ||
691 | if (likely(clk->parent)) | ||
692 | ret = __clk_use(clk->parent); | ||
693 | |||
694 | if (unlikely(ret != 0)) { | ||
695 | clk->usecount--; | ||
696 | return ret; | ||
697 | } | ||
698 | |||
699 | ret = __clk_enable(clk); | ||
700 | |||
701 | if (unlikely(ret != 0) && clk->parent) { | ||
702 | __clk_unuse(clk->parent); | ||
703 | clk->usecount--; | ||
704 | } | ||
705 | } | ||
706 | |||
707 | return ret; | ||
708 | } | ||
709 | |||
710 | |||
711 | int clk_enable(struct clk *clk) | ||
712 | { | ||
713 | unsigned long flags; | ||
714 | int ret; | ||
715 | |||
716 | spin_lock_irqsave(&clockfw_lock, flags); | ||
717 | ret = __clk_enable(clk); | ||
718 | spin_unlock_irqrestore(&clockfw_lock, flags); | ||
719 | return ret; | ||
720 | } | ||
721 | EXPORT_SYMBOL(clk_enable); | ||
722 | |||
723 | |||
724 | void clk_disable(struct clk *clk) | ||
725 | { | ||
726 | unsigned long flags; | ||
727 | |||
728 | spin_lock_irqsave(&clockfw_lock, flags); | ||
729 | __clk_disable(clk); | ||
730 | spin_unlock_irqrestore(&clockfw_lock, flags); | ||
731 | } | ||
732 | EXPORT_SYMBOL(clk_disable); | ||
733 | |||
734 | |||
735 | int clk_use(struct clk *clk) | ||
736 | { | ||
737 | unsigned long flags; | ||
738 | int ret = 0; | ||
739 | |||
740 | spin_lock_irqsave(&clockfw_lock, flags); | ||
741 | ret = __clk_use(clk); | ||
742 | spin_unlock_irqrestore(&clockfw_lock, flags); | ||
743 | return ret; | ||
744 | } | ||
745 | EXPORT_SYMBOL(clk_use); | ||
746 | |||
747 | |||
748 | void clk_unuse(struct clk *clk) | ||
749 | { | ||
750 | unsigned long flags; | ||
751 | |||
752 | spin_lock_irqsave(&clockfw_lock, flags); | ||
753 | __clk_unuse(clk); | ||
754 | spin_unlock_irqrestore(&clockfw_lock, flags); | ||
755 | } | ||
756 | EXPORT_SYMBOL(clk_unuse); | ||
757 | |||
758 | |||
759 | int clk_get_usecount(struct clk *clk) | ||
760 | { | ||
761 | return clk->usecount; | ||
762 | } | ||
763 | EXPORT_SYMBOL(clk_get_usecount); | ||
764 | |||
765 | |||
766 | unsigned long clk_get_rate(struct clk *clk) | ||
767 | { | ||
768 | return clk->rate; | ||
769 | } | ||
770 | EXPORT_SYMBOL(clk_get_rate); | ||
771 | |||
772 | |||
773 | static __u16 verify_ckctl_value(__u16 newval) | ||
774 | { | ||
775 | /* This function checks for following limitations set | ||
776 | * by the hardware (all conditions must be true): | ||
777 | * DSPMMU_CK == DSP_CK or DSPMMU_CK == DSP_CK/2 | ||
778 | * ARM_CK >= TC_CK | ||
779 | * DSP_CK >= TC_CK | ||
780 | * DSPMMU_CK >= TC_CK | ||
781 | * | ||
782 | * In addition following rules are enforced: | ||
783 | * LCD_CK <= TC_CK | ||
784 | * ARMPER_CK <= TC_CK | ||
785 | * | ||
786 | * However, maximum frequencies are not checked for! | ||
787 | */ | ||
788 | __u8 per_exp; | ||
789 | __u8 lcd_exp; | ||
790 | __u8 arm_exp; | ||
791 | __u8 dsp_exp; | ||
792 | __u8 tc_exp; | ||
793 | __u8 dspmmu_exp; | ||
794 | |||
795 | per_exp = (newval >> CKCTL_PERDIV_OFFSET) & 3; | ||
796 | lcd_exp = (newval >> CKCTL_LCDDIV_OFFSET) & 3; | ||
797 | arm_exp = (newval >> CKCTL_ARMDIV_OFFSET) & 3; | ||
798 | dsp_exp = (newval >> CKCTL_DSPDIV_OFFSET) & 3; | ||
799 | tc_exp = (newval >> CKCTL_TCDIV_OFFSET) & 3; | ||
800 | dspmmu_exp = (newval >> CKCTL_DSPMMUDIV_OFFSET) & 3; | ||
801 | |||
802 | if (dspmmu_exp < dsp_exp) | ||
803 | dspmmu_exp = dsp_exp; | ||
804 | if (dspmmu_exp > dsp_exp+1) | ||
805 | dspmmu_exp = dsp_exp+1; | ||
806 | if (tc_exp < arm_exp) | ||
807 | tc_exp = arm_exp; | ||
808 | if (tc_exp < dspmmu_exp) | ||
809 | tc_exp = dspmmu_exp; | ||
810 | if (tc_exp > lcd_exp) | ||
811 | lcd_exp = tc_exp; | ||
812 | if (tc_exp > per_exp) | ||
813 | per_exp = tc_exp; | ||
814 | |||
815 | newval &= 0xf000; | ||
816 | newval |= per_exp << CKCTL_PERDIV_OFFSET; | ||
817 | newval |= lcd_exp << CKCTL_LCDDIV_OFFSET; | ||
818 | newval |= arm_exp << CKCTL_ARMDIV_OFFSET; | ||
819 | newval |= dsp_exp << CKCTL_DSPDIV_OFFSET; | ||
820 | newval |= tc_exp << CKCTL_TCDIV_OFFSET; | ||
821 | newval |= dspmmu_exp << CKCTL_DSPMMUDIV_OFFSET; | ||
822 | |||
823 | return newval; | ||
824 | } | ||
825 | |||
826 | |||
827 | static int calc_dsor_exp(struct clk *clk, unsigned long rate) | ||
828 | { | ||
829 | /* Note: If target frequency is too low, this function will return 4, | ||
830 | * which is invalid value. Caller must check for this value and act | ||
831 | * accordingly. | ||
832 | * | ||
833 | * Note: This function does not check for following limitations set | ||
834 | * by the hardware (all conditions must be true): | ||
835 | * DSPMMU_CK == DSP_CK or DSPMMU_CK == DSP_CK/2 | ||
836 | * ARM_CK >= TC_CK | ||
837 | * DSP_CK >= TC_CK | ||
838 | * DSPMMU_CK >= TC_CK | ||
839 | */ | ||
840 | unsigned long realrate; | ||
841 | struct clk * parent; | ||
842 | unsigned dsor_exp; | ||
843 | |||
844 | if (unlikely(!(clk->flags & RATE_CKCTL))) | ||
845 | return -EINVAL; | ||
846 | |||
847 | parent = clk->parent; | ||
848 | if (unlikely(parent == 0)) | ||
849 | return -EIO; | ||
850 | |||
851 | realrate = parent->rate; | ||
852 | for (dsor_exp=0; dsor_exp<4; dsor_exp++) { | ||
853 | if (realrate <= rate) | ||
854 | break; | ||
855 | |||
856 | realrate /= 2; | ||
857 | } | ||
858 | |||
859 | return dsor_exp; | ||
860 | } | ||
861 | |||
862 | |||
863 | static void ckctl_recalc(struct clk * clk) | ||
864 | { | ||
865 | int dsor; | ||
866 | |||
867 | /* Calculate divisor encoded as 2-bit exponent */ | ||
868 | if (clk->flags & DSP_DOMAIN_CLOCK) { | ||
869 | /* The clock control bits are in DSP domain, | ||
870 | * so api_ck is needed for access. | ||
871 | * Note that DSP_CKCTL virt addr = phys addr, so | ||
872 | * we must use __raw_readw() instead of omap_readw(). | ||
873 | */ | ||
874 | __clk_use(&api_ck); | ||
875 | dsor = 1 << (3 & (__raw_readw(DSP_CKCTL) >> clk->rate_offset)); | ||
876 | __clk_unuse(&api_ck); | ||
877 | } else { | ||
878 | dsor = 1 << (3 & (omap_readw(ARM_CKCTL) >> clk->rate_offset)); | ||
879 | } | ||
880 | if (unlikely(clk->rate == clk->parent->rate / dsor)) | ||
881 | return; /* No change, quick exit */ | ||
882 | clk->rate = clk->parent->rate / dsor; | ||
883 | |||
884 | if (unlikely(clk->flags & RATE_PROPAGATES)) | ||
885 | propagate_rate(clk); | ||
886 | } | ||
887 | |||
888 | |||
889 | long clk_round_rate(struct clk *clk, unsigned long rate) | ||
890 | { | ||
891 | int dsor_exp; | ||
892 | |||
893 | if (clk->flags & RATE_FIXED) | ||
894 | return clk->rate; | ||
895 | |||
896 | if (clk->flags & RATE_CKCTL) { | ||
897 | dsor_exp = calc_dsor_exp(clk, rate); | ||
898 | if (dsor_exp < 0) | ||
899 | return dsor_exp; | ||
900 | if (dsor_exp > 3) | ||
901 | dsor_exp = 3; | ||
902 | return clk->parent->rate / (1 << dsor_exp); | ||
903 | } | ||
904 | |||
905 | if(clk->round_rate != 0) | ||
906 | return clk->round_rate(clk, rate); | ||
907 | |||
908 | return clk->rate; | ||
909 | } | ||
910 | EXPORT_SYMBOL(clk_round_rate); | ||
911 | |||
912 | |||
913 | static void propagate_rate(struct clk * clk) | ||
914 | { | ||
915 | struct clk ** clkp; | ||
916 | |||
917 | for (clkp = onchip_clks; clkp < onchip_clks+ARRAY_SIZE(onchip_clks); clkp++) { | ||
918 | if (likely((*clkp)->parent != clk)) continue; | ||
919 | if (likely((*clkp)->recalc)) | ||
920 | (*clkp)->recalc(*clkp); | ||
921 | } | ||
922 | } | ||
923 | |||
924 | |||
925 | static int select_table_rate(struct clk * clk, unsigned long rate) | ||
926 | { | ||
927 | /* Find the highest supported frequency <= rate and switch to it */ | ||
928 | struct mpu_rate * ptr; | ||
929 | |||
930 | if (clk != &virtual_ck_mpu) | ||
931 | return -EINVAL; | ||
932 | |||
933 | for (ptr = rate_table; ptr->rate; ptr++) { | ||
934 | if (ptr->xtal != ck_ref.rate) | ||
935 | continue; | ||
936 | |||
937 | /* DPLL1 cannot be reprogrammed without risking system crash */ | ||
938 | if (likely(ck_dpll1.rate!=0) && ptr->pll_rate != ck_dpll1.rate) | ||
939 | continue; | ||
940 | |||
941 | /* Can check only after xtal frequency check */ | ||
942 | if (ptr->rate <= rate) | ||
943 | break; | ||
944 | } | ||
945 | |||
946 | if (!ptr->rate) | ||
947 | return -EINVAL; | ||
948 | |||
949 | if (!ptr->rate) | ||
950 | return -EINVAL; | ||
951 | |||
952 | if (unlikely(ck_dpll1.rate == 0)) { | ||
953 | omap_writew(ptr->dpllctl_val, DPLL_CTL); | ||
954 | ck_dpll1.rate = ptr->pll_rate; | ||
955 | } | ||
956 | omap_writew(ptr->ckctl_val, ARM_CKCTL); | ||
957 | propagate_rate(&ck_dpll1); | ||
958 | return 0; | ||
959 | } | ||
960 | |||
961 | |||
962 | static long round_to_table_rate(struct clk * clk, unsigned long rate) | ||
963 | { | ||
964 | /* Find the highest supported frequency <= rate */ | ||
965 | struct mpu_rate * ptr; | ||
966 | long highest_rate; | ||
967 | |||
968 | if (clk != &virtual_ck_mpu) | ||
969 | return -EINVAL; | ||
970 | |||
971 | highest_rate = -EINVAL; | ||
972 | |||
973 | for (ptr = rate_table; ptr->rate; ptr++) { | ||
974 | if (ptr->xtal != ck_ref.rate) | ||
975 | continue; | ||
976 | |||
977 | highest_rate = ptr->rate; | ||
978 | |||
979 | /* Can check only after xtal frequency check */ | ||
980 | if (ptr->rate <= rate) | ||
981 | break; | ||
982 | } | ||
983 | |||
984 | return highest_rate; | ||
985 | } | ||
986 | |||
987 | |||
988 | int clk_set_rate(struct clk *clk, unsigned long rate) | ||
989 | { | ||
990 | int ret = -EINVAL; | ||
991 | int dsor_exp; | ||
992 | __u16 regval; | ||
993 | unsigned long flags; | ||
994 | |||
995 | if (clk->flags & RATE_CKCTL) { | ||
996 | dsor_exp = calc_dsor_exp(clk, rate); | ||
997 | if (dsor_exp > 3) | ||
998 | dsor_exp = -EINVAL; | ||
999 | if (dsor_exp < 0) | ||
1000 | return dsor_exp; | ||
1001 | |||
1002 | spin_lock_irqsave(&clockfw_lock, flags); | ||
1003 | regval = omap_readw(ARM_CKCTL); | ||
1004 | regval &= ~(3 << clk->rate_offset); | ||
1005 | regval |= dsor_exp << clk->rate_offset; | ||
1006 | regval = verify_ckctl_value(regval); | ||
1007 | omap_writew(regval, ARM_CKCTL); | ||
1008 | clk->rate = clk->parent->rate / (1 << dsor_exp); | ||
1009 | spin_unlock_irqrestore(&clockfw_lock, flags); | ||
1010 | ret = 0; | ||
1011 | } else if(clk->set_rate != 0) { | ||
1012 | spin_lock_irqsave(&clockfw_lock, flags); | ||
1013 | ret = clk->set_rate(clk, rate); | ||
1014 | spin_unlock_irqrestore(&clockfw_lock, flags); | ||
1015 | } | ||
1016 | |||
1017 | if (unlikely(ret == 0 && (clk->flags & RATE_PROPAGATES))) | ||
1018 | propagate_rate(clk); | ||
1019 | |||
1020 | return ret; | ||
1021 | } | ||
1022 | EXPORT_SYMBOL(clk_set_rate); | ||
1023 | |||
1024 | |||
1025 | static unsigned calc_ext_dsor(unsigned long rate) | ||
1026 | { | ||
1027 | unsigned dsor; | ||
1028 | |||
1029 | /* MCLK and BCLK divisor selection is not linear: | ||
1030 | * freq = 96MHz / dsor | ||
1031 | * | ||
1032 | * RATIO_SEL range: dsor <-> RATIO_SEL | ||
1033 | * 0..6: (RATIO_SEL+2) <-> (dsor-2) | ||
1034 | * 6..48: (8+(RATIO_SEL-6)*2) <-> ((dsor-8)/2+6) | ||
1035 | * Minimum dsor is 2 and maximum is 96. Odd divisors starting from 9 | ||
1036 | * can not be used. | ||
1037 | */ | ||
1038 | for (dsor = 2; dsor < 96; ++dsor) { | ||
1039 | if ((dsor & 1) && dsor > 8) | ||
1040 | continue; | ||
1041 | if (rate >= 96000000 / dsor) | ||
1042 | break; | ||
1043 | } | ||
1044 | return dsor; | ||
1045 | } | ||
1046 | |||
1047 | /* Only needed on 1510 */ | ||
1048 | static int set_uart_rate(struct clk * clk, unsigned long rate) | ||
1049 | { | ||
1050 | unsigned int val; | ||
1051 | |||
1052 | val = omap_readl(clk->enable_reg); | ||
1053 | if (rate == 12000000) | ||
1054 | val &= ~(1 << clk->enable_bit); | ||
1055 | else if (rate == 48000000) | ||
1056 | val |= (1 << clk->enable_bit); | ||
1057 | else | ||
1058 | return -EINVAL; | ||
1059 | omap_writel(val, clk->enable_reg); | ||
1060 | clk->rate = rate; | ||
1061 | |||
1062 | return 0; | ||
1063 | } | ||
1064 | |||
1065 | static int set_ext_clk_rate(struct clk * clk, unsigned long rate) | ||
1066 | { | ||
1067 | unsigned dsor; | ||
1068 | __u16 ratio_bits; | ||
1069 | |||
1070 | dsor = calc_ext_dsor(rate); | ||
1071 | clk->rate = 96000000 / dsor; | ||
1072 | if (dsor > 8) | ||
1073 | ratio_bits = ((dsor - 8) / 2 + 6) << 2; | ||
1074 | else | ||
1075 | ratio_bits = (dsor - 2) << 2; | ||
1076 | |||
1077 | ratio_bits |= omap_readw(clk->enable_reg) & ~0xfd; | ||
1078 | omap_writew(ratio_bits, clk->enable_reg); | ||
1079 | |||
1080 | return 0; | ||
1081 | } | ||
1082 | |||
1083 | |||
1084 | static long round_ext_clk_rate(struct clk * clk, unsigned long rate) | ||
1085 | { | ||
1086 | return 96000000 / calc_ext_dsor(rate); | ||
1087 | } | ||
1088 | |||
1089 | |||
1090 | static void init_ext_clk(struct clk * clk) | ||
1091 | { | ||
1092 | unsigned dsor; | ||
1093 | __u16 ratio_bits; | ||
1094 | |||
1095 | /* Determine current rate and ensure clock is based on 96MHz APLL */ | ||
1096 | ratio_bits = omap_readw(clk->enable_reg) & ~1; | ||
1097 | omap_writew(ratio_bits, clk->enable_reg); | ||
1098 | |||
1099 | ratio_bits = (ratio_bits & 0xfc) >> 2; | ||
1100 | if (ratio_bits > 6) | ||
1101 | dsor = (ratio_bits - 6) * 2 + 8; | ||
1102 | else | ||
1103 | dsor = ratio_bits + 2; | ||
1104 | |||
1105 | clk-> rate = 96000000 / dsor; | ||
1106 | } | ||
1107 | |||
1108 | |||
1109 | int clk_register(struct clk *clk) | ||
1110 | { | ||
1111 | down(&clocks_sem); | ||
1112 | list_add(&clk->node, &clocks); | ||
1113 | if (clk->init) | ||
1114 | clk->init(clk); | ||
1115 | up(&clocks_sem); | ||
1116 | return 0; | ||
1117 | } | ||
1118 | EXPORT_SYMBOL(clk_register); | ||
1119 | |||
1120 | void clk_unregister(struct clk *clk) | ||
1121 | { | ||
1122 | down(&clocks_sem); | ||
1123 | list_del(&clk->node); | ||
1124 | up(&clocks_sem); | ||
1125 | } | ||
1126 | EXPORT_SYMBOL(clk_unregister); | ||
1127 | |||
1128 | #ifdef CONFIG_OMAP_RESET_CLOCKS | ||
1129 | /* | ||
1130 | * Resets some clocks that may be left on from bootloader, | ||
1131 | * but leaves serial clocks on. See also omap_late_clk_reset(). | ||
1132 | */ | ||
1133 | static inline void omap_early_clk_reset(void) | ||
1134 | { | ||
1135 | //omap_writel(0x3 << 29, MOD_CONF_CTRL_0); | ||
1136 | } | ||
1137 | #else | ||
1138 | #define omap_early_clk_reset() {} | ||
1139 | #endif | ||
1140 | |||
1141 | int __init clk_init(void) | ||
1142 | { | ||
1143 | struct clk ** clkp; | ||
1144 | const struct omap_clock_config *info; | ||
1145 | int crystal_type = 0; /* Default 12 MHz */ | ||
1146 | |||
1147 | omap_early_clk_reset(); | ||
1148 | |||
1149 | for (clkp = onchip_clks; clkp < onchip_clks+ARRAY_SIZE(onchip_clks); clkp++) { | ||
1150 | if (((*clkp)->flags &CLOCK_IN_OMAP1510) && cpu_is_omap1510()) { | ||
1151 | clk_register(*clkp); | ||
1152 | continue; | ||
1153 | } | ||
1154 | |||
1155 | if (((*clkp)->flags &CLOCK_IN_OMAP16XX) && cpu_is_omap16xx()) { | ||
1156 | clk_register(*clkp); | ||
1157 | continue; | ||
1158 | } | ||
1159 | |||
1160 | if (((*clkp)->flags &CLOCK_IN_OMAP730) && cpu_is_omap730()) { | ||
1161 | clk_register(*clkp); | ||
1162 | continue; | ||
1163 | } | ||
1164 | } | ||
1165 | |||
1166 | info = omap_get_config(OMAP_TAG_CLOCK, struct omap_clock_config); | ||
1167 | if (info != NULL) { | ||
1168 | if (!cpu_is_omap1510()) | ||
1169 | crystal_type = info->system_clock_type; | ||
1170 | } | ||
1171 | |||
1172 | #if defined(CONFIG_ARCH_OMAP730) | ||
1173 | ck_ref.rate = 13000000; | ||
1174 | #elif defined(CONFIG_ARCH_OMAP16XX) | ||
1175 | if (crystal_type == 2) | ||
1176 | ck_ref.rate = 19200000; | ||
1177 | #endif | ||
1178 | |||
1179 | printk("Clocks: ARM_SYSST: 0x%04x DPLL_CTL: 0x%04x ARM_CKCTL: 0x%04x\n", | ||
1180 | omap_readw(ARM_SYSST), omap_readw(DPLL_CTL), | ||
1181 | omap_readw(ARM_CKCTL)); | ||
1182 | |||
1183 | /* We want to be in syncronous scalable mode */ | ||
1184 | omap_writew(0x1000, ARM_SYSST); | ||
1185 | |||
1186 | #ifdef CONFIG_OMAP_CLOCKS_SET_BY_BOOTLOADER | ||
1187 | /* Use values set by bootloader. Determine PLL rate and recalculate | ||
1188 | * dependent clocks as if kernel had changed PLL or divisors. | ||
1189 | */ | ||
1190 | { | ||
1191 | unsigned pll_ctl_val = omap_readw(DPLL_CTL); | ||
1192 | |||
1193 | ck_dpll1.rate = ck_ref.rate; /* Base xtal rate */ | ||
1194 | if (pll_ctl_val & 0x10) { | ||
1195 | /* PLL enabled, apply multiplier and divisor */ | ||
1196 | if (pll_ctl_val & 0xf80) | ||
1197 | ck_dpll1.rate *= (pll_ctl_val & 0xf80) >> 7; | ||
1198 | ck_dpll1.rate /= ((pll_ctl_val & 0x60) >> 5) + 1; | ||
1199 | } else { | ||
1200 | /* PLL disabled, apply bypass divisor */ | ||
1201 | switch (pll_ctl_val & 0xc) { | ||
1202 | case 0: | ||
1203 | break; | ||
1204 | case 0x4: | ||
1205 | ck_dpll1.rate /= 2; | ||
1206 | break; | ||
1207 | default: | ||
1208 | ck_dpll1.rate /= 4; | ||
1209 | break; | ||
1210 | } | ||
1211 | } | ||
1212 | } | ||
1213 | propagate_rate(&ck_dpll1); | ||
1214 | #else | ||
1215 | /* Find the highest supported frequency and enable it */ | ||
1216 | if (select_table_rate(&virtual_ck_mpu, ~0)) { | ||
1217 | printk(KERN_ERR "System frequencies not set. Check your config.\n"); | ||
1218 | /* Guess sane values (60MHz) */ | ||
1219 | omap_writew(0x2290, DPLL_CTL); | ||
1220 | omap_writew(0x1005, ARM_CKCTL); | ||
1221 | ck_dpll1.rate = 60000000; | ||
1222 | propagate_rate(&ck_dpll1); | ||
1223 | } | ||
1224 | #endif | ||
1225 | /* Cache rates for clocks connected to ck_ref (not dpll1) */ | ||
1226 | propagate_rate(&ck_ref); | ||
1227 | printk(KERN_INFO "Clocking rate (xtal/DPLL1/MPU): %ld.%01ld/%ld/%ld MHz\n", | ||
1228 | ck_ref.rate / 1000000, (ck_ref.rate / 100000) % 10, | ||
1229 | ck_dpll1.rate, arm_ck.rate); | ||
1230 | |||
1231 | #ifdef CONFIG_MACH_OMAP_PERSEUS2 | ||
1232 | /* Select slicer output as OMAP input clock */ | ||
1233 | omap_writew(omap_readw(OMAP730_PCC_UPLD_CTRL) & ~0x1, OMAP730_PCC_UPLD_CTRL); | ||
1234 | #endif | ||
1235 | |||
1236 | /* Turn off DSP and ARM_TIMXO. Make sure ARM_INTHCK is not divided */ | ||
1237 | omap_writew(omap_readw(ARM_CKCTL) & 0x0fff, ARM_CKCTL); | ||
1238 | |||
1239 | /* Put DSP/MPUI into reset until needed */ | ||
1240 | omap_writew(0, ARM_RSTCT1); | ||
1241 | omap_writew(1, ARM_RSTCT2); | ||
1242 | omap_writew(0x400, ARM_IDLECT1); | ||
1243 | |||
1244 | /* | ||
1245 | * According to OMAP5910 Erratum SYS_DMA_1, bit DMACK_REQ (bit 8) | ||
1246 | * of the ARM_IDLECT2 register must be set to zero. The power-on | ||
1247 | * default value of this bit is one. | ||
1248 | */ | ||
1249 | omap_writew(0x0000, ARM_IDLECT2); /* Turn LCD clock off also */ | ||
1250 | |||
1251 | /* | ||
1252 | * Only enable those clocks we will need, let the drivers | ||
1253 | * enable other clocks as necessary | ||
1254 | */ | ||
1255 | clk_use(&armper_ck); | ||
1256 | clk_use(&armxor_ck); | ||
1257 | clk_use(&armtim_ck); | ||
1258 | |||
1259 | if (cpu_is_omap1510()) | ||
1260 | clk_enable(&arm_gpio_ck); | ||
1261 | |||
1262 | return 0; | ||
1263 | } | ||
1264 | |||
1265 | |||
1266 | #ifdef CONFIG_OMAP_RESET_CLOCKS | ||
1267 | |||
1268 | static int __init omap_late_clk_reset(void) | ||
1269 | { | ||
1270 | /* Turn off all unused clocks */ | ||
1271 | struct clk *p; | ||
1272 | __u32 regval32; | ||
1273 | |||
1274 | omap_writew(0, SOFT_REQ_REG); | ||
1275 | omap_writew(0, SOFT_REQ_REG2); | ||
1276 | |||
1277 | list_for_each_entry(p, &clocks, node) { | ||
1278 | if (p->usecount > 0 || (p->flags & ALWAYS_ENABLED) || | ||
1279 | p->enable_reg == 0) | ||
1280 | continue; | ||
1281 | |||
1282 | /* Assume no DSP clocks have been activated by bootloader */ | ||
1283 | if (p->flags & DSP_DOMAIN_CLOCK) | ||
1284 | continue; | ||
1285 | |||
1286 | /* Is the clock already disabled? */ | ||
1287 | if (p->flags & ENABLE_REG_32BIT) { | ||
1288 | if (p->flags & VIRTUAL_IO_ADDRESS) | ||
1289 | regval32 = __raw_readl(p->enable_reg); | ||
1290 | else | ||
1291 | regval32 = omap_readl(p->enable_reg); | ||
1292 | } else { | ||
1293 | if (p->flags & VIRTUAL_IO_ADDRESS) | ||
1294 | regval32 = __raw_readw(p->enable_reg); | ||
1295 | else | ||
1296 | regval32 = omap_readw(p->enable_reg); | ||
1297 | } | ||
1298 | |||
1299 | if ((regval32 & (1 << p->enable_bit)) == 0) | ||
1300 | continue; | ||
1301 | |||
1302 | /* FIXME: This clock seems to be necessary but no-one | ||
1303 | * has asked for its activation. */ | ||
1304 | if (p == &tc2_ck // FIX: pm.c (SRAM), CCP, Camera | ||
1305 | || p == &ck_dpll1out // FIX: SoSSI, SSR | ||
1306 | || p == &arm_gpio_ck // FIX: GPIO code for 1510 | ||
1307 | ) { | ||
1308 | printk(KERN_INFO "FIXME: Clock \"%s\" seems unused\n", | ||
1309 | p->name); | ||
1310 | continue; | ||
1311 | } | ||
1312 | |||
1313 | printk(KERN_INFO "Disabling unused clock \"%s\"... ", p->name); | ||
1314 | __clk_disable(p); | ||
1315 | printk(" done\n"); | ||
1316 | } | ||
1317 | |||
1318 | return 0; | ||
1319 | } | ||
1320 | |||
1321 | late_initcall(omap_late_clk_reset); | ||
1322 | |||
1323 | #endif | ||