diff options
author | Tony Lindgren <tony@atomide.com> | 2005-11-10 09:26:48 -0500 |
---|---|---|
committer | Russell King <rmk+kernel@arm.linux.org.uk> | 2005-11-10 09:26:48 -0500 |
commit | 3179a019391f0f8081245fd564a5f1be308ba64f (patch) | |
tree | afdc1200f17b0ca97e04baa7c2cc2d4d2883e0c9 /arch/arm/mach-omap1/clock.c | |
parent | a7918f39bbe59fe76f43743bdb6bb8b0bdefd94a (diff) |
[ARM] 3141/1: OMAP 1/5: Update omap1 specific files
Patch from Tony Lindgren
This patch syncs the mainline kernel with linux-omap tree.
The highlights of the patch are:
- Omap1 serial pport and framebuffer init updates by Imre Deak
- Add support for omap310 processor and Palm Tungsten E PDA
by Laurent Gonzales, Romain Goyet, et al. Omap310 and
omap1510 processors are now handled as omap15xx.
- Omap1 specific changes to shared omap clock framework
by Tony Lindgren
- Omap1 specific changes to shared omap pin mux framework
by Tony Lindgren
- Other misc fixes, such as update memory timings for smc91x,
omap1 specific device initialization etc.
Signed-off-by: Tony Lindgren <tony@atomide.com>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
Diffstat (limited to 'arch/arm/mach-omap1/clock.c')
-rw-r--r-- | arch/arm/mach-omap1/clock.c | 792 |
1 files changed, 792 insertions, 0 deletions
diff --git a/arch/arm/mach-omap1/clock.c b/arch/arm/mach-omap1/clock.c new file mode 100644 index 000000000000..4277eee44ed5 --- /dev/null +++ b/arch/arm/mach-omap1/clock.c | |||
@@ -0,0 +1,792 @@ | |||
1 | /* | ||
2 | * linux/arch/arm/mach-omap1/clock.c | ||
3 | * | ||
4 | * Copyright (C) 2004 - 2005 Nokia corporation | ||
5 | * Written by Tuukka Tikkanen <tuukka.tikkanen@elektrobit.com> | ||
6 | * | ||
7 | * Modified to use omap shared clock framework by | ||
8 | * Tony Lindgren <tony@atomide.com> | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of the GNU General Public License version 2 as | ||
12 | * published by the Free Software Foundation. | ||
13 | */ | ||
14 | #include <linux/module.h> | ||
15 | #include <linux/kernel.h> | ||
16 | #include <linux/list.h> | ||
17 | #include <linux/errno.h> | ||
18 | #include <linux/err.h> | ||
19 | |||
20 | #include <asm/io.h> | ||
21 | #include <asm/hardware/clock.h> | ||
22 | |||
23 | #include <asm/arch/usb.h> | ||
24 | #include <asm/arch/clock.h> | ||
25 | #include <asm/arch/sram.h> | ||
26 | |||
27 | #include "clock.h" | ||
28 | |||
29 | __u32 arm_idlect1_mask; | ||
30 | |||
31 | /*------------------------------------------------------------------------- | ||
32 | * Omap1 specific clock functions | ||
33 | *-------------------------------------------------------------------------*/ | ||
34 | |||
35 | static void omap1_watchdog_recalc(struct clk * clk) | ||
36 | { | ||
37 | clk->rate = clk->parent->rate / 14; | ||
38 | } | ||
39 | |||
40 | static void omap1_uart_recalc(struct clk * clk) | ||
41 | { | ||
42 | unsigned int val = omap_readl(clk->enable_reg); | ||
43 | if (val & clk->enable_bit) | ||
44 | clk->rate = 48000000; | ||
45 | else | ||
46 | clk->rate = 12000000; | ||
47 | } | ||
48 | |||
49 | static int omap1_clk_enable_dsp_domain(struct clk *clk) | ||
50 | { | ||
51 | int retval; | ||
52 | |||
53 | retval = omap1_clk_use(&api_ck.clk); | ||
54 | if (!retval) { | ||
55 | retval = omap1_clk_enable(clk); | ||
56 | omap1_clk_unuse(&api_ck.clk); | ||
57 | } | ||
58 | |||
59 | return retval; | ||
60 | } | ||
61 | |||
62 | static void omap1_clk_disable_dsp_domain(struct clk *clk) | ||
63 | { | ||
64 | if (omap1_clk_use(&api_ck.clk) == 0) { | ||
65 | omap1_clk_disable(clk); | ||
66 | omap1_clk_unuse(&api_ck.clk); | ||
67 | } | ||
68 | } | ||
69 | |||
70 | static int omap1_clk_enable_uart_functional(struct clk *clk) | ||
71 | { | ||
72 | int ret; | ||
73 | struct uart_clk *uclk; | ||
74 | |||
75 | ret = omap1_clk_enable(clk); | ||
76 | if (ret == 0) { | ||
77 | /* Set smart idle acknowledgement mode */ | ||
78 | uclk = (struct uart_clk *)clk; | ||
79 | omap_writeb((omap_readb(uclk->sysc_addr) & ~0x10) | 8, | ||
80 | uclk->sysc_addr); | ||
81 | } | ||
82 | |||
83 | return ret; | ||
84 | } | ||
85 | |||
86 | static void omap1_clk_disable_uart_functional(struct clk *clk) | ||
87 | { | ||
88 | struct uart_clk *uclk; | ||
89 | |||
90 | /* Set force idle acknowledgement mode */ | ||
91 | uclk = (struct uart_clk *)clk; | ||
92 | omap_writeb((omap_readb(uclk->sysc_addr) & ~0x18), uclk->sysc_addr); | ||
93 | |||
94 | omap1_clk_disable(clk); | ||
95 | } | ||
96 | |||
97 | static void omap1_clk_allow_idle(struct clk *clk) | ||
98 | { | ||
99 | struct arm_idlect1_clk * iclk = (struct arm_idlect1_clk *)clk; | ||
100 | |||
101 | if (!(clk->flags & CLOCK_IDLE_CONTROL)) | ||
102 | return; | ||
103 | |||
104 | if (iclk->no_idle_count > 0 && !(--iclk->no_idle_count)) | ||
105 | arm_idlect1_mask |= 1 << iclk->idlect_shift; | ||
106 | } | ||
107 | |||
108 | static void omap1_clk_deny_idle(struct clk *clk) | ||
109 | { | ||
110 | struct arm_idlect1_clk * iclk = (struct arm_idlect1_clk *)clk; | ||
111 | |||
112 | if (!(clk->flags & CLOCK_IDLE_CONTROL)) | ||
113 | return; | ||
114 | |||
115 | if (iclk->no_idle_count++ == 0) | ||
116 | arm_idlect1_mask &= ~(1 << iclk->idlect_shift); | ||
117 | } | ||
118 | |||
119 | static __u16 verify_ckctl_value(__u16 newval) | ||
120 | { | ||
121 | /* This function checks for following limitations set | ||
122 | * by the hardware (all conditions must be true): | ||
123 | * DSPMMU_CK == DSP_CK or DSPMMU_CK == DSP_CK/2 | ||
124 | * ARM_CK >= TC_CK | ||
125 | * DSP_CK >= TC_CK | ||
126 | * DSPMMU_CK >= TC_CK | ||
127 | * | ||
128 | * In addition following rules are enforced: | ||
129 | * LCD_CK <= TC_CK | ||
130 | * ARMPER_CK <= TC_CK | ||
131 | * | ||
132 | * However, maximum frequencies are not checked for! | ||
133 | */ | ||
134 | __u8 per_exp; | ||
135 | __u8 lcd_exp; | ||
136 | __u8 arm_exp; | ||
137 | __u8 dsp_exp; | ||
138 | __u8 tc_exp; | ||
139 | __u8 dspmmu_exp; | ||
140 | |||
141 | per_exp = (newval >> CKCTL_PERDIV_OFFSET) & 3; | ||
142 | lcd_exp = (newval >> CKCTL_LCDDIV_OFFSET) & 3; | ||
143 | arm_exp = (newval >> CKCTL_ARMDIV_OFFSET) & 3; | ||
144 | dsp_exp = (newval >> CKCTL_DSPDIV_OFFSET) & 3; | ||
145 | tc_exp = (newval >> CKCTL_TCDIV_OFFSET) & 3; | ||
146 | dspmmu_exp = (newval >> CKCTL_DSPMMUDIV_OFFSET) & 3; | ||
147 | |||
148 | if (dspmmu_exp < dsp_exp) | ||
149 | dspmmu_exp = dsp_exp; | ||
150 | if (dspmmu_exp > dsp_exp+1) | ||
151 | dspmmu_exp = dsp_exp+1; | ||
152 | if (tc_exp < arm_exp) | ||
153 | tc_exp = arm_exp; | ||
154 | if (tc_exp < dspmmu_exp) | ||
155 | tc_exp = dspmmu_exp; | ||
156 | if (tc_exp > lcd_exp) | ||
157 | lcd_exp = tc_exp; | ||
158 | if (tc_exp > per_exp) | ||
159 | per_exp = tc_exp; | ||
160 | |||
161 | newval &= 0xf000; | ||
162 | newval |= per_exp << CKCTL_PERDIV_OFFSET; | ||
163 | newval |= lcd_exp << CKCTL_LCDDIV_OFFSET; | ||
164 | newval |= arm_exp << CKCTL_ARMDIV_OFFSET; | ||
165 | newval |= dsp_exp << CKCTL_DSPDIV_OFFSET; | ||
166 | newval |= tc_exp << CKCTL_TCDIV_OFFSET; | ||
167 | newval |= dspmmu_exp << CKCTL_DSPMMUDIV_OFFSET; | ||
168 | |||
169 | return newval; | ||
170 | } | ||
171 | |||
172 | static int calc_dsor_exp(struct clk *clk, unsigned long rate) | ||
173 | { | ||
174 | /* Note: If target frequency is too low, this function will return 4, | ||
175 | * which is invalid value. Caller must check for this value and act | ||
176 | * accordingly. | ||
177 | * | ||
178 | * Note: This function does not check for following limitations set | ||
179 | * by the hardware (all conditions must be true): | ||
180 | * DSPMMU_CK == DSP_CK or DSPMMU_CK == DSP_CK/2 | ||
181 | * ARM_CK >= TC_CK | ||
182 | * DSP_CK >= TC_CK | ||
183 | * DSPMMU_CK >= TC_CK | ||
184 | */ | ||
185 | unsigned long realrate; | ||
186 | struct clk * parent; | ||
187 | unsigned dsor_exp; | ||
188 | |||
189 | if (unlikely(!(clk->flags & RATE_CKCTL))) | ||
190 | return -EINVAL; | ||
191 | |||
192 | parent = clk->parent; | ||
193 | if (unlikely(parent == 0)) | ||
194 | return -EIO; | ||
195 | |||
196 | realrate = parent->rate; | ||
197 | for (dsor_exp=0; dsor_exp<4; dsor_exp++) { | ||
198 | if (realrate <= rate) | ||
199 | break; | ||
200 | |||
201 | realrate /= 2; | ||
202 | } | ||
203 | |||
204 | return dsor_exp; | ||
205 | } | ||
206 | |||
207 | static void omap1_ckctl_recalc(struct clk * clk) | ||
208 | { | ||
209 | int dsor; | ||
210 | |||
211 | /* Calculate divisor encoded as 2-bit exponent */ | ||
212 | dsor = 1 << (3 & (omap_readw(ARM_CKCTL) >> clk->rate_offset)); | ||
213 | |||
214 | if (unlikely(clk->rate == clk->parent->rate / dsor)) | ||
215 | return; /* No change, quick exit */ | ||
216 | clk->rate = clk->parent->rate / dsor; | ||
217 | |||
218 | if (unlikely(clk->flags & RATE_PROPAGATES)) | ||
219 | propagate_rate(clk); | ||
220 | } | ||
221 | |||
222 | static void omap1_ckctl_recalc_dsp_domain(struct clk * clk) | ||
223 | { | ||
224 | int dsor; | ||
225 | |||
226 | /* Calculate divisor encoded as 2-bit exponent | ||
227 | * | ||
228 | * The clock control bits are in DSP domain, | ||
229 | * so api_ck is needed for access. | ||
230 | * Note that DSP_CKCTL virt addr = phys addr, so | ||
231 | * we must use __raw_readw() instead of omap_readw(). | ||
232 | */ | ||
233 | omap1_clk_use(&api_ck.clk); | ||
234 | dsor = 1 << (3 & (__raw_readw(DSP_CKCTL) >> clk->rate_offset)); | ||
235 | omap1_clk_unuse(&api_ck.clk); | ||
236 | |||
237 | if (unlikely(clk->rate == clk->parent->rate / dsor)) | ||
238 | return; /* No change, quick exit */ | ||
239 | clk->rate = clk->parent->rate / dsor; | ||
240 | |||
241 | if (unlikely(clk->flags & RATE_PROPAGATES)) | ||
242 | propagate_rate(clk); | ||
243 | } | ||
244 | |||
245 | /* MPU virtual clock functions */ | ||
246 | static int omap1_select_table_rate(struct clk * clk, unsigned long rate) | ||
247 | { | ||
248 | /* Find the highest supported frequency <= rate and switch to it */ | ||
249 | struct mpu_rate * ptr; | ||
250 | |||
251 | if (clk != &virtual_ck_mpu) | ||
252 | return -EINVAL; | ||
253 | |||
254 | for (ptr = rate_table; ptr->rate; ptr++) { | ||
255 | if (ptr->xtal != ck_ref.rate) | ||
256 | continue; | ||
257 | |||
258 | /* DPLL1 cannot be reprogrammed without risking system crash */ | ||
259 | if (likely(ck_dpll1.rate!=0) && ptr->pll_rate != ck_dpll1.rate) | ||
260 | continue; | ||
261 | |||
262 | /* Can check only after xtal frequency check */ | ||
263 | if (ptr->rate <= rate) | ||
264 | break; | ||
265 | } | ||
266 | |||
267 | if (!ptr->rate) | ||
268 | return -EINVAL; | ||
269 | |||
270 | /* | ||
271 | * In most cases we should not need to reprogram DPLL. | ||
272 | * Reprogramming the DPLL is tricky, it must be done from SRAM. | ||
273 | */ | ||
274 | omap_sram_reprogram_clock(ptr->dpllctl_val, ptr->ckctl_val); | ||
275 | |||
276 | ck_dpll1.rate = ptr->pll_rate; | ||
277 | propagate_rate(&ck_dpll1); | ||
278 | return 0; | ||
279 | } | ||
280 | |||
281 | static int omap1_clk_set_rate_dsp_domain(struct clk *clk, unsigned long rate) | ||
282 | { | ||
283 | int ret = -EINVAL; | ||
284 | int dsor_exp; | ||
285 | __u16 regval; | ||
286 | |||
287 | if (clk->flags & RATE_CKCTL) { | ||
288 | dsor_exp = calc_dsor_exp(clk, rate); | ||
289 | if (dsor_exp > 3) | ||
290 | dsor_exp = -EINVAL; | ||
291 | if (dsor_exp < 0) | ||
292 | return dsor_exp; | ||
293 | |||
294 | regval = __raw_readw(DSP_CKCTL); | ||
295 | regval &= ~(3 << clk->rate_offset); | ||
296 | regval |= dsor_exp << clk->rate_offset; | ||
297 | __raw_writew(regval, DSP_CKCTL); | ||
298 | clk->rate = clk->parent->rate / (1 << dsor_exp); | ||
299 | ret = 0; | ||
300 | } | ||
301 | |||
302 | if (unlikely(ret == 0 && (clk->flags & RATE_PROPAGATES))) | ||
303 | propagate_rate(clk); | ||
304 | |||
305 | return ret; | ||
306 | } | ||
307 | |||
308 | static long omap1_round_to_table_rate(struct clk * clk, unsigned long rate) | ||
309 | { | ||
310 | /* Find the highest supported frequency <= rate */ | ||
311 | struct mpu_rate * ptr; | ||
312 | long highest_rate; | ||
313 | |||
314 | if (clk != &virtual_ck_mpu) | ||
315 | return -EINVAL; | ||
316 | |||
317 | highest_rate = -EINVAL; | ||
318 | |||
319 | for (ptr = rate_table; ptr->rate; ptr++) { | ||
320 | if (ptr->xtal != ck_ref.rate) | ||
321 | continue; | ||
322 | |||
323 | highest_rate = ptr->rate; | ||
324 | |||
325 | /* Can check only after xtal frequency check */ | ||
326 | if (ptr->rate <= rate) | ||
327 | break; | ||
328 | } | ||
329 | |||
330 | return highest_rate; | ||
331 | } | ||
332 | |||
333 | static unsigned calc_ext_dsor(unsigned long rate) | ||
334 | { | ||
335 | unsigned dsor; | ||
336 | |||
337 | /* MCLK and BCLK divisor selection is not linear: | ||
338 | * freq = 96MHz / dsor | ||
339 | * | ||
340 | * RATIO_SEL range: dsor <-> RATIO_SEL | ||
341 | * 0..6: (RATIO_SEL+2) <-> (dsor-2) | ||
342 | * 6..48: (8+(RATIO_SEL-6)*2) <-> ((dsor-8)/2+6) | ||
343 | * Minimum dsor is 2 and maximum is 96. Odd divisors starting from 9 | ||
344 | * can not be used. | ||
345 | */ | ||
346 | for (dsor = 2; dsor < 96; ++dsor) { | ||
347 | if ((dsor & 1) && dsor > 8) | ||
348 | continue; | ||
349 | if (rate >= 96000000 / dsor) | ||
350 | break; | ||
351 | } | ||
352 | return dsor; | ||
353 | } | ||
354 | |||
355 | /* Only needed on 1510 */ | ||
356 | static int omap1_set_uart_rate(struct clk * clk, unsigned long rate) | ||
357 | { | ||
358 | unsigned int val; | ||
359 | |||
360 | val = omap_readl(clk->enable_reg); | ||
361 | if (rate == 12000000) | ||
362 | val &= ~(1 << clk->enable_bit); | ||
363 | else if (rate == 48000000) | ||
364 | val |= (1 << clk->enable_bit); | ||
365 | else | ||
366 | return -EINVAL; | ||
367 | omap_writel(val, clk->enable_reg); | ||
368 | clk->rate = rate; | ||
369 | |||
370 | return 0; | ||
371 | } | ||
372 | |||
373 | /* External clock (MCLK & BCLK) functions */ | ||
374 | static int omap1_set_ext_clk_rate(struct clk * clk, unsigned long rate) | ||
375 | { | ||
376 | unsigned dsor; | ||
377 | __u16 ratio_bits; | ||
378 | |||
379 | dsor = calc_ext_dsor(rate); | ||
380 | clk->rate = 96000000 / dsor; | ||
381 | if (dsor > 8) | ||
382 | ratio_bits = ((dsor - 8) / 2 + 6) << 2; | ||
383 | else | ||
384 | ratio_bits = (dsor - 2) << 2; | ||
385 | |||
386 | ratio_bits |= omap_readw(clk->enable_reg) & ~0xfd; | ||
387 | omap_writew(ratio_bits, clk->enable_reg); | ||
388 | |||
389 | return 0; | ||
390 | } | ||
391 | |||
392 | static long omap1_round_ext_clk_rate(struct clk * clk, unsigned long rate) | ||
393 | { | ||
394 | return 96000000 / calc_ext_dsor(rate); | ||
395 | } | ||
396 | |||
397 | static void omap1_init_ext_clk(struct clk * clk) | ||
398 | { | ||
399 | unsigned dsor; | ||
400 | __u16 ratio_bits; | ||
401 | |||
402 | /* Determine current rate and ensure clock is based on 96MHz APLL */ | ||
403 | ratio_bits = omap_readw(clk->enable_reg) & ~1; | ||
404 | omap_writew(ratio_bits, clk->enable_reg); | ||
405 | |||
406 | ratio_bits = (ratio_bits & 0xfc) >> 2; | ||
407 | if (ratio_bits > 6) | ||
408 | dsor = (ratio_bits - 6) * 2 + 8; | ||
409 | else | ||
410 | dsor = ratio_bits + 2; | ||
411 | |||
412 | clk-> rate = 96000000 / dsor; | ||
413 | } | ||
414 | |||
415 | static int omap1_clk_use(struct clk *clk) | ||
416 | { | ||
417 | int ret = 0; | ||
418 | if (clk->usecount++ == 0) { | ||
419 | if (likely(clk->parent)) { | ||
420 | ret = omap1_clk_use(clk->parent); | ||
421 | |||
422 | if (unlikely(ret != 0)) { | ||
423 | clk->usecount--; | ||
424 | return ret; | ||
425 | } | ||
426 | |||
427 | if (clk->flags & CLOCK_NO_IDLE_PARENT) | ||
428 | if (!cpu_is_omap24xx()) | ||
429 | omap1_clk_deny_idle(clk->parent); | ||
430 | } | ||
431 | |||
432 | ret = clk->enable(clk); | ||
433 | |||
434 | if (unlikely(ret != 0) && clk->parent) { | ||
435 | omap1_clk_unuse(clk->parent); | ||
436 | clk->usecount--; | ||
437 | } | ||
438 | } | ||
439 | |||
440 | return ret; | ||
441 | } | ||
442 | |||
443 | static void omap1_clk_unuse(struct clk *clk) | ||
444 | { | ||
445 | if (clk->usecount > 0 && !(--clk->usecount)) { | ||
446 | clk->disable(clk); | ||
447 | if (likely(clk->parent)) { | ||
448 | omap1_clk_unuse(clk->parent); | ||
449 | if (clk->flags & CLOCK_NO_IDLE_PARENT) | ||
450 | if (!cpu_is_omap24xx()) | ||
451 | omap1_clk_allow_idle(clk->parent); | ||
452 | } | ||
453 | } | ||
454 | } | ||
455 | |||
456 | static int omap1_clk_enable(struct clk *clk) | ||
457 | { | ||
458 | __u16 regval16; | ||
459 | __u32 regval32; | ||
460 | |||
461 | if (clk->flags & ALWAYS_ENABLED) | ||
462 | return 0; | ||
463 | |||
464 | if (unlikely(clk->enable_reg == 0)) { | ||
465 | printk(KERN_ERR "clock.c: Enable for %s without enable code\n", | ||
466 | clk->name); | ||
467 | return 0; | ||
468 | } | ||
469 | |||
470 | if (clk->flags & ENABLE_REG_32BIT) { | ||
471 | if (clk->flags & VIRTUAL_IO_ADDRESS) { | ||
472 | regval32 = __raw_readl(clk->enable_reg); | ||
473 | regval32 |= (1 << clk->enable_bit); | ||
474 | __raw_writel(regval32, clk->enable_reg); | ||
475 | } else { | ||
476 | regval32 = omap_readl(clk->enable_reg); | ||
477 | regval32 |= (1 << clk->enable_bit); | ||
478 | omap_writel(regval32, clk->enable_reg); | ||
479 | } | ||
480 | } else { | ||
481 | if (clk->flags & VIRTUAL_IO_ADDRESS) { | ||
482 | regval16 = __raw_readw(clk->enable_reg); | ||
483 | regval16 |= (1 << clk->enable_bit); | ||
484 | __raw_writew(regval16, clk->enable_reg); | ||
485 | } else { | ||
486 | regval16 = omap_readw(clk->enable_reg); | ||
487 | regval16 |= (1 << clk->enable_bit); | ||
488 | omap_writew(regval16, clk->enable_reg); | ||
489 | } | ||
490 | } | ||
491 | |||
492 | return 0; | ||
493 | } | ||
494 | |||
495 | static void omap1_clk_disable(struct clk *clk) | ||
496 | { | ||
497 | __u16 regval16; | ||
498 | __u32 regval32; | ||
499 | |||
500 | if (clk->enable_reg == 0) | ||
501 | return; | ||
502 | |||
503 | if (clk->flags & ENABLE_REG_32BIT) { | ||
504 | if (clk->flags & VIRTUAL_IO_ADDRESS) { | ||
505 | regval32 = __raw_readl(clk->enable_reg); | ||
506 | regval32 &= ~(1 << clk->enable_bit); | ||
507 | __raw_writel(regval32, clk->enable_reg); | ||
508 | } else { | ||
509 | regval32 = omap_readl(clk->enable_reg); | ||
510 | regval32 &= ~(1 << clk->enable_bit); | ||
511 | omap_writel(regval32, clk->enable_reg); | ||
512 | } | ||
513 | } else { | ||
514 | if (clk->flags & VIRTUAL_IO_ADDRESS) { | ||
515 | regval16 = __raw_readw(clk->enable_reg); | ||
516 | regval16 &= ~(1 << clk->enable_bit); | ||
517 | __raw_writew(regval16, clk->enable_reg); | ||
518 | } else { | ||
519 | regval16 = omap_readw(clk->enable_reg); | ||
520 | regval16 &= ~(1 << clk->enable_bit); | ||
521 | omap_writew(regval16, clk->enable_reg); | ||
522 | } | ||
523 | } | ||
524 | } | ||
525 | |||
526 | static long omap1_clk_round_rate(struct clk *clk, unsigned long rate) | ||
527 | { | ||
528 | int dsor_exp; | ||
529 | |||
530 | if (clk->flags & RATE_FIXED) | ||
531 | return clk->rate; | ||
532 | |||
533 | if (clk->flags & RATE_CKCTL) { | ||
534 | dsor_exp = calc_dsor_exp(clk, rate); | ||
535 | if (dsor_exp < 0) | ||
536 | return dsor_exp; | ||
537 | if (dsor_exp > 3) | ||
538 | dsor_exp = 3; | ||
539 | return clk->parent->rate / (1 << dsor_exp); | ||
540 | } | ||
541 | |||
542 | if(clk->round_rate != 0) | ||
543 | return clk->round_rate(clk, rate); | ||
544 | |||
545 | return clk->rate; | ||
546 | } | ||
547 | |||
548 | static int omap1_clk_set_rate(struct clk *clk, unsigned long rate) | ||
549 | { | ||
550 | int ret = -EINVAL; | ||
551 | int dsor_exp; | ||
552 | __u16 regval; | ||
553 | |||
554 | if (clk->set_rate) | ||
555 | ret = clk->set_rate(clk, rate); | ||
556 | else if (clk->flags & RATE_CKCTL) { | ||
557 | dsor_exp = calc_dsor_exp(clk, rate); | ||
558 | if (dsor_exp > 3) | ||
559 | dsor_exp = -EINVAL; | ||
560 | if (dsor_exp < 0) | ||
561 | return dsor_exp; | ||
562 | |||
563 | regval = omap_readw(ARM_CKCTL); | ||
564 | regval &= ~(3 << clk->rate_offset); | ||
565 | regval |= dsor_exp << clk->rate_offset; | ||
566 | regval = verify_ckctl_value(regval); | ||
567 | omap_writew(regval, ARM_CKCTL); | ||
568 | clk->rate = clk->parent->rate / (1 << dsor_exp); | ||
569 | ret = 0; | ||
570 | } | ||
571 | |||
572 | if (unlikely(ret == 0 && (clk->flags & RATE_PROPAGATES))) | ||
573 | propagate_rate(clk); | ||
574 | |||
575 | return ret; | ||
576 | } | ||
577 | |||
578 | /*------------------------------------------------------------------------- | ||
579 | * Omap1 clock reset and init functions | ||
580 | *-------------------------------------------------------------------------*/ | ||
581 | |||
582 | #ifdef CONFIG_OMAP_RESET_CLOCKS | ||
583 | /* | ||
584 | * Resets some clocks that may be left on from bootloader, | ||
585 | * but leaves serial clocks on. See also omap_late_clk_reset(). | ||
586 | */ | ||
587 | static inline void omap1_early_clk_reset(void) | ||
588 | { | ||
589 | //omap_writel(0x3 << 29, MOD_CONF_CTRL_0); | ||
590 | } | ||
591 | |||
592 | static int __init omap1_late_clk_reset(void) | ||
593 | { | ||
594 | /* Turn off all unused clocks */ | ||
595 | struct clk *p; | ||
596 | __u32 regval32; | ||
597 | |||
598 | /* USB_REQ_EN will be disabled later if necessary (usb_dc_ck) */ | ||
599 | regval32 = omap_readw(SOFT_REQ_REG) & (1 << 4); | ||
600 | omap_writew(regval32, SOFT_REQ_REG); | ||
601 | omap_writew(0, SOFT_REQ_REG2); | ||
602 | |||
603 | list_for_each_entry(p, &clocks, node) { | ||
604 | if (p->usecount > 0 || (p->flags & ALWAYS_ENABLED) || | ||
605 | p->enable_reg == 0) | ||
606 | continue; | ||
607 | |||
608 | /* Clocks in the DSP domain need api_ck. Just assume bootloader | ||
609 | * has not enabled any DSP clocks */ | ||
610 | if ((u32)p->enable_reg == DSP_IDLECT2) { | ||
611 | printk(KERN_INFO "Skipping reset check for DSP domain " | ||
612 | "clock \"%s\"\n", p->name); | ||
613 | continue; | ||
614 | } | ||
615 | |||
616 | /* Is the clock already disabled? */ | ||
617 | if (p->flags & ENABLE_REG_32BIT) { | ||
618 | if (p->flags & VIRTUAL_IO_ADDRESS) | ||
619 | regval32 = __raw_readl(p->enable_reg); | ||
620 | else | ||
621 | regval32 = omap_readl(p->enable_reg); | ||
622 | } else { | ||
623 | if (p->flags & VIRTUAL_IO_ADDRESS) | ||
624 | regval32 = __raw_readw(p->enable_reg); | ||
625 | else | ||
626 | regval32 = omap_readw(p->enable_reg); | ||
627 | } | ||
628 | |||
629 | if ((regval32 & (1 << p->enable_bit)) == 0) | ||
630 | continue; | ||
631 | |||
632 | /* FIXME: This clock seems to be necessary but no-one | ||
633 | * has asked for its activation. */ | ||
634 | if (p == &tc2_ck // FIX: pm.c (SRAM), CCP, Camera | ||
635 | || p == &ck_dpll1out.clk // FIX: SoSSI, SSR | ||
636 | || p == &arm_gpio_ck // FIX: GPIO code for 1510 | ||
637 | ) { | ||
638 | printk(KERN_INFO "FIXME: Clock \"%s\" seems unused\n", | ||
639 | p->name); | ||
640 | continue; | ||
641 | } | ||
642 | |||
643 | printk(KERN_INFO "Disabling unused clock \"%s\"... ", p->name); | ||
644 | p->disable(p); | ||
645 | printk(" done\n"); | ||
646 | } | ||
647 | |||
648 | return 0; | ||
649 | } | ||
650 | late_initcall(omap1_late_clk_reset); | ||
651 | |||
652 | #else | ||
653 | #define omap1_early_clk_reset() {} | ||
654 | #endif | ||
655 | |||
656 | static struct clk_functions omap1_clk_functions = { | ||
657 | .clk_use = omap1_clk_use, | ||
658 | .clk_unuse = omap1_clk_unuse, | ||
659 | .clk_round_rate = omap1_clk_round_rate, | ||
660 | .clk_set_rate = omap1_clk_set_rate, | ||
661 | }; | ||
662 | |||
663 | int __init omap1_clk_init(void) | ||
664 | { | ||
665 | struct clk ** clkp; | ||
666 | const struct omap_clock_config *info; | ||
667 | int crystal_type = 0; /* Default 12 MHz */ | ||
668 | |||
669 | omap1_early_clk_reset(); | ||
670 | clk_init(&omap1_clk_functions); | ||
671 | |||
672 | /* By default all idlect1 clocks are allowed to idle */ | ||
673 | arm_idlect1_mask = ~0; | ||
674 | |||
675 | for (clkp = onchip_clks; clkp < onchip_clks+ARRAY_SIZE(onchip_clks); clkp++) { | ||
676 | if (((*clkp)->flags &CLOCK_IN_OMAP1510) && cpu_is_omap1510()) { | ||
677 | clk_register(*clkp); | ||
678 | continue; | ||
679 | } | ||
680 | |||
681 | if (((*clkp)->flags &CLOCK_IN_OMAP16XX) && cpu_is_omap16xx()) { | ||
682 | clk_register(*clkp); | ||
683 | continue; | ||
684 | } | ||
685 | |||
686 | if (((*clkp)->flags &CLOCK_IN_OMAP730) && cpu_is_omap730()) { | ||
687 | clk_register(*clkp); | ||
688 | continue; | ||
689 | } | ||
690 | } | ||
691 | |||
692 | info = omap_get_config(OMAP_TAG_CLOCK, struct omap_clock_config); | ||
693 | if (info != NULL) { | ||
694 | if (!cpu_is_omap1510()) | ||
695 | crystal_type = info->system_clock_type; | ||
696 | } | ||
697 | |||
698 | #if defined(CONFIG_ARCH_OMAP730) | ||
699 | ck_ref.rate = 13000000; | ||
700 | #elif defined(CONFIG_ARCH_OMAP16XX) | ||
701 | if (crystal_type == 2) | ||
702 | ck_ref.rate = 19200000; | ||
703 | #endif | ||
704 | |||
705 | printk("Clocks: ARM_SYSST: 0x%04x DPLL_CTL: 0x%04x ARM_CKCTL: 0x%04x\n", | ||
706 | omap_readw(ARM_SYSST), omap_readw(DPLL_CTL), | ||
707 | omap_readw(ARM_CKCTL)); | ||
708 | |||
709 | /* We want to be in syncronous scalable mode */ | ||
710 | omap_writew(0x1000, ARM_SYSST); | ||
711 | |||
712 | #ifdef CONFIG_OMAP_CLOCKS_SET_BY_BOOTLOADER | ||
713 | /* Use values set by bootloader. Determine PLL rate and recalculate | ||
714 | * dependent clocks as if kernel had changed PLL or divisors. | ||
715 | */ | ||
716 | { | ||
717 | unsigned pll_ctl_val = omap_readw(DPLL_CTL); | ||
718 | |||
719 | ck_dpll1.rate = ck_ref.rate; /* Base xtal rate */ | ||
720 | if (pll_ctl_val & 0x10) { | ||
721 | /* PLL enabled, apply multiplier and divisor */ | ||
722 | if (pll_ctl_val & 0xf80) | ||
723 | ck_dpll1.rate *= (pll_ctl_val & 0xf80) >> 7; | ||
724 | ck_dpll1.rate /= ((pll_ctl_val & 0x60) >> 5) + 1; | ||
725 | } else { | ||
726 | /* PLL disabled, apply bypass divisor */ | ||
727 | switch (pll_ctl_val & 0xc) { | ||
728 | case 0: | ||
729 | break; | ||
730 | case 0x4: | ||
731 | ck_dpll1.rate /= 2; | ||
732 | break; | ||
733 | default: | ||
734 | ck_dpll1.rate /= 4; | ||
735 | break; | ||
736 | } | ||
737 | } | ||
738 | } | ||
739 | propagate_rate(&ck_dpll1); | ||
740 | #else | ||
741 | /* Find the highest supported frequency and enable it */ | ||
742 | if (omap1_select_table_rate(&virtual_ck_mpu, ~0)) { | ||
743 | printk(KERN_ERR "System frequencies not set. Check your config.\n"); | ||
744 | /* Guess sane values (60MHz) */ | ||
745 | omap_writew(0x2290, DPLL_CTL); | ||
746 | omap_writew(0x1005, ARM_CKCTL); | ||
747 | ck_dpll1.rate = 60000000; | ||
748 | propagate_rate(&ck_dpll1); | ||
749 | } | ||
750 | #endif | ||
751 | /* Cache rates for clocks connected to ck_ref (not dpll1) */ | ||
752 | propagate_rate(&ck_ref); | ||
753 | printk(KERN_INFO "Clocking rate (xtal/DPLL1/MPU): " | ||
754 | "%ld.%01ld/%ld.%01ld/%ld.%01ld MHz\n", | ||
755 | ck_ref.rate / 1000000, (ck_ref.rate / 100000) % 10, | ||
756 | ck_dpll1.rate / 1000000, (ck_dpll1.rate / 100000) % 10, | ||
757 | arm_ck.rate / 1000000, (arm_ck.rate / 100000) % 10); | ||
758 | |||
759 | #ifdef CONFIG_MACH_OMAP_PERSEUS2 | ||
760 | /* Select slicer output as OMAP input clock */ | ||
761 | omap_writew(omap_readw(OMAP730_PCC_UPLD_CTRL) & ~0x1, OMAP730_PCC_UPLD_CTRL); | ||
762 | #endif | ||
763 | |||
764 | /* Turn off DSP and ARM_TIMXO. Make sure ARM_INTHCK is not divided */ | ||
765 | omap_writew(omap_readw(ARM_CKCTL) & 0x0fff, ARM_CKCTL); | ||
766 | |||
767 | /* Put DSP/MPUI into reset until needed */ | ||
768 | omap_writew(0, ARM_RSTCT1); | ||
769 | omap_writew(1, ARM_RSTCT2); | ||
770 | omap_writew(0x400, ARM_IDLECT1); | ||
771 | |||
772 | /* | ||
773 | * According to OMAP5910 Erratum SYS_DMA_1, bit DMACK_REQ (bit 8) | ||
774 | * of the ARM_IDLECT2 register must be set to zero. The power-on | ||
775 | * default value of this bit is one. | ||
776 | */ | ||
777 | omap_writew(0x0000, ARM_IDLECT2); /* Turn LCD clock off also */ | ||
778 | |||
779 | /* | ||
780 | * Only enable those clocks we will need, let the drivers | ||
781 | * enable other clocks as necessary | ||
782 | */ | ||
783 | clk_use(&armper_ck.clk); | ||
784 | clk_use(&armxor_ck.clk); | ||
785 | clk_use(&armtim_ck.clk); /* This should be done by timer code */ | ||
786 | |||
787 | if (cpu_is_omap1510()) | ||
788 | clk_enable(&arm_gpio_ck); | ||
789 | |||
790 | return 0; | ||
791 | } | ||
792 | |||