diff options
Diffstat (limited to 'arch/arm/mach-omap2/clock24xx.c')
-rw-r--r-- | arch/arm/mach-omap2/clock24xx.c | 722 |
1 files changed, 0 insertions, 722 deletions
diff --git a/arch/arm/mach-omap2/clock24xx.c b/arch/arm/mach-omap2/clock24xx.c index c3ccac1b7218..615b511c68c9 100644 --- a/arch/arm/mach-omap2/clock24xx.c +++ b/arch/arm/mach-omap2/clock24xx.c | |||
@@ -109,29 +109,6 @@ static u32 omap2_get_dpll_rate_24xx(struct clk *tclk) | |||
109 | return dpll_clk; | 109 | return dpll_clk; |
110 | } | 110 | } |
111 | 111 | ||
112 | static void omap2_followparent_recalc(struct clk *clk) | ||
113 | { | ||
114 | followparent_recalc(clk); | ||
115 | } | ||
116 | |||
117 | static void omap2_propagate_rate(struct clk * clk) | ||
118 | { | ||
119 | if (!(clk->flags & RATE_FIXED)) | ||
120 | clk->rate = clk->parent->rate; | ||
121 | |||
122 | propagate_rate(clk); | ||
123 | } | ||
124 | |||
125 | #ifdef OLD_CK | ||
126 | static void omap2_set_osc_ck(int enable) | ||
127 | { | ||
128 | if (enable) | ||
129 | PRCM_CLKSRC_CTRL &= ~(0x3 << 3); | ||
130 | else | ||
131 | PRCM_CLKSRC_CTRL |= 0x3 << 3; | ||
132 | } | ||
133 | #endif /* OLD_CK */ | ||
134 | |||
135 | /* Enable an APLL if off */ | 112 | /* Enable an APLL if off */ |
136 | static int omap2_clk_fixed_enable(struct clk *clk) | 113 | static int omap2_clk_fixed_enable(struct clk *clk) |
137 | { | 114 | { |
@@ -163,84 +140,6 @@ static int omap2_clk_fixed_enable(struct clk *clk) | |||
163 | return 0; | 140 | return 0; |
164 | } | 141 | } |
165 | 142 | ||
166 | #ifdef OLD_CK | ||
167 | static void omap2_clk_wait_ready(struct clk *clk) | ||
168 | { | ||
169 | unsigned long reg, other_reg, st_reg; | ||
170 | u32 bit; | ||
171 | int i; | ||
172 | |||
173 | reg = (unsigned long) clk->enable_reg; | ||
174 | if (reg == (unsigned long) &CM_FCLKEN1_CORE || | ||
175 | reg == (unsigned long) &CM_FCLKEN2_CORE) | ||
176 | other_reg = (reg & ~0xf0) | 0x10; | ||
177 | else if (reg == (unsigned long) &CM_ICLKEN1_CORE || | ||
178 | reg == (unsigned long) &CM_ICLKEN2_CORE) | ||
179 | other_reg = (reg & ~0xf0) | 0x00; | ||
180 | else | ||
181 | return; | ||
182 | |||
183 | /* No check for DSS or cam clocks */ | ||
184 | if ((reg & 0x0f) == 0) { | ||
185 | if (clk->enable_bit <= 1 || clk->enable_bit == 31) | ||
186 | return; | ||
187 | } | ||
188 | |||
189 | /* Check if both functional and interface clocks | ||
190 | * are running. */ | ||
191 | bit = 1 << clk->enable_bit; | ||
192 | if (!(__raw_readl(other_reg) & bit)) | ||
193 | return; | ||
194 | st_reg = (other_reg & ~0xf0) | 0x20; | ||
195 | i = 0; | ||
196 | while (!(__raw_readl(st_reg) & bit)) { | ||
197 | i++; | ||
198 | if (i == 100000) { | ||
199 | printk(KERN_ERR "Timeout enabling clock %s\n", clk->name); | ||
200 | break; | ||
201 | } | ||
202 | } | ||
203 | if (i) | ||
204 | pr_debug("Clock %s stable after %d loops\n", clk->name, i); | ||
205 | } | ||
206 | |||
207 | /* Enables clock without considering parent dependencies or use count | ||
208 | * REVISIT: Maybe change this to use clk->enable like on omap1? | ||
209 | */ | ||
210 | static int _omap2_clk_enable(struct clk * clk) | ||
211 | { | ||
212 | u32 regval32; | ||
213 | |||
214 | if (clk->flags & ALWAYS_ENABLED) | ||
215 | return 0; | ||
216 | |||
217 | if (unlikely(clk == &osc_ck)) { | ||
218 | omap2_set_osc_ck(1); | ||
219 | return 0; | ||
220 | } | ||
221 | |||
222 | if (unlikely(clk->enable_reg == 0)) { | ||
223 | printk(KERN_ERR "clock.c: Enable for %s without enable code\n", | ||
224 | clk->name); | ||
225 | return 0; | ||
226 | } | ||
227 | |||
228 | if (clk->enable_reg == (void __iomem *)&CM_CLKEN_PLL) { | ||
229 | omap2_clk_fixed_enable(clk); | ||
230 | return 0; | ||
231 | } | ||
232 | |||
233 | regval32 = __raw_readl(clk->enable_reg); | ||
234 | regval32 |= (1 << clk->enable_bit); | ||
235 | __raw_writel(regval32, clk->enable_reg); | ||
236 | wmb(); | ||
237 | |||
238 | omap2_clk_wait_ready(clk); | ||
239 | |||
240 | return 0; | ||
241 | } | ||
242 | #endif /* OLD_CK */ | ||
243 | |||
244 | /* Stop APLL */ | 143 | /* Stop APLL */ |
245 | static void omap2_clk_fixed_disable(struct clk *clk) | 144 | static void omap2_clk_fixed_disable(struct clk *clk) |
246 | { | 145 | { |
@@ -251,65 +150,6 @@ static void omap2_clk_fixed_disable(struct clk *clk) | |||
251 | cm_write_mod_reg(cval, PLL_MOD, CM_CLKEN); | 150 | cm_write_mod_reg(cval, PLL_MOD, CM_CLKEN); |
252 | } | 151 | } |
253 | 152 | ||
254 | #ifdef OLD_CK | ||
255 | /* Disables clock without considering parent dependencies or use count */ | ||
256 | static void _omap2_clk_disable(struct clk *clk) | ||
257 | { | ||
258 | u32 regval32; | ||
259 | |||
260 | if (unlikely(clk == &osc_ck)) { | ||
261 | omap2_set_osc_ck(0); | ||
262 | return; | ||
263 | } | ||
264 | |||
265 | if (clk->enable_reg == 0) | ||
266 | return; | ||
267 | |||
268 | if (clk->enable_reg == (void __iomem *)&CM_CLKEN_PLL) { | ||
269 | omap2_clk_fixed_disable(clk); | ||
270 | return; | ||
271 | } | ||
272 | |||
273 | regval32 = __raw_readl(clk->enable_reg); | ||
274 | regval32 &= ~(1 << clk->enable_bit); | ||
275 | __raw_writel(regval32, clk->enable_reg); | ||
276 | wmb(); | ||
277 | } | ||
278 | |||
279 | static int omap2_clk_enable(struct clk *clk) | ||
280 | { | ||
281 | int ret = 0; | ||
282 | |||
283 | if (clk->usecount++ == 0) { | ||
284 | if (likely((u32)clk->parent)) | ||
285 | ret = omap2_clk_enable(clk->parent); | ||
286 | |||
287 | if (unlikely(ret != 0)) { | ||
288 | clk->usecount--; | ||
289 | return ret; | ||
290 | } | ||
291 | |||
292 | ret = _omap2_clk_enable(clk); | ||
293 | |||
294 | if (unlikely(ret != 0) && clk->parent) { | ||
295 | omap2_clk_disable(clk->parent); | ||
296 | clk->usecount--; | ||
297 | } | ||
298 | } | ||
299 | |||
300 | return ret; | ||
301 | } | ||
302 | |||
303 | static void omap2_clk_disable(struct clk *clk) | ||
304 | { | ||
305 | if (clk->usecount > 0 && !(--clk->usecount)) { | ||
306 | _omap2_clk_disable(clk); | ||
307 | if (likely((u32)clk->parent)) | ||
308 | omap2_clk_disable(clk->parent); | ||
309 | } | ||
310 | } | ||
311 | #endif /* OLD_CK */ | ||
312 | |||
313 | /* | 153 | /* |
314 | * Uses the current prcm set to tell if a rate is valid. | 154 | * Uses the current prcm set to tell if a rate is valid. |
315 | * You can go slower, but not faster within a given rate set. | 155 | * You can go slower, but not faster within a given rate set. |
@@ -343,195 +183,6 @@ static u32 omap2_dpll_round_rate(unsigned long target_rate) | |||
343 | 183 | ||
344 | } | 184 | } |
345 | 185 | ||
346 | #ifdef OLD_CK | ||
347 | /* | ||
348 | * Used for clocks that are part of CLKSEL_xyz governed clocks. | ||
349 | * REVISIT: Maybe change to use clk->enable() functions like on omap1? | ||
350 | */ | ||
351 | static void omap2_clksel_recalc(struct clk * clk) | ||
352 | { | ||
353 | u32 fixed = 0, div = 0; | ||
354 | |||
355 | if (clk == &dpll_ck) { | ||
356 | clk->rate = omap2_get_dpll_rate(clk); | ||
357 | fixed = 1; | ||
358 | div = 0; | ||
359 | } | ||
360 | |||
361 | if (clk == &iva1_mpu_int_ifck) { | ||
362 | div = 2; | ||
363 | fixed = 1; | ||
364 | } | ||
365 | |||
366 | if ((clk == &dss1_fck) && ((CM_CLKSEL1_CORE & (0x1f << 8)) == 0)) { | ||
367 | clk->rate = sys_ck.rate; | ||
368 | return; | ||
369 | } | ||
370 | |||
371 | if (!fixed) { | ||
372 | div = omap2_clksel_get_divisor(clk); | ||
373 | if (div == 0) | ||
374 | return; | ||
375 | } | ||
376 | |||
377 | if (div != 0) { | ||
378 | if (unlikely(clk->rate == clk->parent->rate / div)) | ||
379 | return; | ||
380 | clk->rate = clk->parent->rate / div; | ||
381 | } | ||
382 | |||
383 | if (unlikely(clk->flags & RATE_PROPAGATES)) | ||
384 | propagate_rate(clk); | ||
385 | } | ||
386 | |||
387 | /* | ||
388 | * Finds best divider value in an array based on the source and target | ||
389 | * rates. The divider array must be sorted with smallest divider first. | ||
390 | */ | ||
391 | static inline u32 omap2_divider_from_table(u32 size, u32 *div_array, | ||
392 | u32 src_rate, u32 tgt_rate) | ||
393 | { | ||
394 | int i, test_rate; | ||
395 | |||
396 | if (div_array == NULL) | ||
397 | return ~1; | ||
398 | |||
399 | for (i=0; i < size; i++) { | ||
400 | test_rate = src_rate / *div_array; | ||
401 | if (test_rate <= tgt_rate) | ||
402 | return *div_array; | ||
403 | ++div_array; | ||
404 | } | ||
405 | |||
406 | return ~0; /* No acceptable divider */ | ||
407 | } | ||
408 | |||
409 | /* | ||
410 | * Find divisor for the given clock and target rate. | ||
411 | * | ||
412 | * Note that this will not work for clocks which are part of CONFIG_PARTICIPANT, | ||
413 | * they are only settable as part of virtual_prcm set. | ||
414 | */ | ||
415 | static u32 omap2_clksel_round_rate(struct clk *tclk, u32 target_rate, | ||
416 | u32 *new_div) | ||
417 | { | ||
418 | u32 gfx_div[] = {2, 3, 4}; | ||
419 | u32 sysclkout_div[] = {1, 2, 4, 8, 16}; | ||
420 | u32 dss1_div[] = {1, 2, 3, 4, 5, 6, 8, 9, 12, 16}; | ||
421 | u32 vylnq_div[] = {1, 2, 3, 4, 6, 8, 9, 12, 16, 18}; | ||
422 | u32 best_div = ~0, asize = 0; | ||
423 | u32 *div_array = NULL; | ||
424 | |||
425 | switch (tclk->flags & SRC_RATE_SEL_MASK) { | ||
426 | case CM_GFX_SEL1: | ||
427 | asize = 3; | ||
428 | div_array = gfx_div; | ||
429 | break; | ||
430 | case CM_PLL_SEL1: | ||
431 | return omap2_dpll_round_rate(target_rate); | ||
432 | case CM_SYSCLKOUT_SEL1: | ||
433 | asize = 5; | ||
434 | div_array = sysclkout_div; | ||
435 | break; | ||
436 | case CM_CORE_SEL1: | ||
437 | if(tclk == &dss1_fck){ | ||
438 | if(tclk->parent == &core_ck){ | ||
439 | asize = 10; | ||
440 | div_array = dss1_div; | ||
441 | } else { | ||
442 | *new_div = 0; /* fixed clk */ | ||
443 | return(tclk->parent->rate); | ||
444 | } | ||
445 | } else if((tclk == &vlynq_fck) && cpu_is_omap2420()){ | ||
446 | if(tclk->parent == &core_ck){ | ||
447 | asize = 10; | ||
448 | div_array = vylnq_div; | ||
449 | } else { | ||
450 | *new_div = 0; /* fixed clk */ | ||
451 | return(tclk->parent->rate); | ||
452 | } | ||
453 | } | ||
454 | break; | ||
455 | } | ||
456 | |||
457 | best_div = omap2_divider_from_table(asize, div_array, | ||
458 | tclk->parent->rate, target_rate); | ||
459 | if (best_div == ~0){ | ||
460 | *new_div = 1; | ||
461 | return best_div; /* signal error */ | ||
462 | } | ||
463 | |||
464 | *new_div = best_div; | ||
465 | return (tclk->parent->rate / best_div); | ||
466 | } | ||
467 | |||
468 | /* Given a clock and a rate apply a clock specific rounding function */ | ||
469 | static long omap2_clk_round_rate(struct clk *clk, unsigned long rate) | ||
470 | { | ||
471 | u32 new_div = 0; | ||
472 | int valid_rate; | ||
473 | |||
474 | if (clk->flags & RATE_FIXED) | ||
475 | return clk->rate; | ||
476 | |||
477 | if (clk->flags & RATE_CKCTL) { | ||
478 | valid_rate = omap2_clksel_round_rate(clk, rate, &new_div); | ||
479 | return valid_rate; | ||
480 | } | ||
481 | |||
482 | if (clk->round_rate != 0) | ||
483 | return clk->round_rate(clk, rate); | ||
484 | |||
485 | return clk->rate; | ||
486 | } | ||
487 | |||
488 | /* | ||
489 | * Check the DLL lock state, and return tue if running in unlock mode. | ||
490 | * This is needed to compensate for the shifted DLL value in unlock mode. | ||
491 | */ | ||
492 | static u32 omap2_dll_force_needed(void) | ||
493 | { | ||
494 | u32 dll_state = SDRC_DLLA_CTRL; /* dlla and dllb are a set */ | ||
495 | |||
496 | if ((dll_state & (1 << 2)) == (1 << 2)) | ||
497 | return 1; | ||
498 | else | ||
499 | return 0; | ||
500 | } | ||
501 | |||
502 | static u32 omap2_reprogram_sdrc(u32 level, u32 force) | ||
503 | { | ||
504 | u32 slow_dll_ctrl, fast_dll_ctrl, m_type; | ||
505 | u32 prev = curr_perf_level, flags; | ||
506 | |||
507 | if ((curr_perf_level == level) && !force) | ||
508 | return prev; | ||
509 | |||
510 | m_type = omap2_memory_get_type(); | ||
511 | slow_dll_ctrl = omap2_memory_get_slow_dll_ctrl(); | ||
512 | fast_dll_ctrl = omap2_memory_get_fast_dll_ctrl(); | ||
513 | |||
514 | if (level == PRCM_HALF_SPEED) { | ||
515 | local_irq_save(flags); | ||
516 | PRCM_VOLTSETUP = 0xffff; | ||
517 | omap2_sram_reprogram_sdrc(PRCM_HALF_SPEED, | ||
518 | slow_dll_ctrl, m_type); | ||
519 | curr_perf_level = PRCM_HALF_SPEED; | ||
520 | local_irq_restore(flags); | ||
521 | } | ||
522 | if (level == PRCM_FULL_SPEED) { | ||
523 | local_irq_save(flags); | ||
524 | PRCM_VOLTSETUP = 0xffff; | ||
525 | omap2_sram_reprogram_sdrc(PRCM_FULL_SPEED, | ||
526 | fast_dll_ctrl, m_type); | ||
527 | curr_perf_level = PRCM_FULL_SPEED; | ||
528 | local_irq_restore(flags); | ||
529 | } | ||
530 | |||
531 | return prev; | ||
532 | } | ||
533 | #endif /* OLD_CK */ | ||
534 | |||
535 | static void omap2_dpll_recalc(struct clk *clk) | 186 | static void omap2_dpll_recalc(struct clk *clk) |
536 | { | 187 | { |
537 | clk->rate = omap2_get_dpll_rate_24xx(clk); | 188 | clk->rate = omap2_get_dpll_rate_24xx(clk); |
@@ -656,359 +307,6 @@ static long omap2_round_to_table_rate(struct clk *clk, unsigned long rate) | |||
656 | return highest_rate; | 307 | return highest_rate; |
657 | } | 308 | } |
658 | 309 | ||
659 | #ifdef OLD_CK | ||
660 | /* | ||
661 | * omap2_convert_field_to_div() - turn field value into integer divider | ||
662 | */ | ||
663 | static u32 omap2_clksel_to_divisor(u32 div_sel, u32 field_val) | ||
664 | { | ||
665 | u32 i; | ||
666 | u32 clkout_array[] = {1, 2, 4, 8, 16}; | ||
667 | |||
668 | if ((div_sel & SRC_RATE_SEL_MASK) == CM_SYSCLKOUT_SEL1) { | ||
669 | for (i = 0; i < 5; i++) { | ||
670 | if (field_val == i) | ||
671 | return clkout_array[i]; | ||
672 | } | ||
673 | return ~0; | ||
674 | } else | ||
675 | return field_val; | ||
676 | } | ||
677 | |||
678 | /* | ||
679 | * Returns the CLKSEL divider register value | ||
680 | * REVISIT: This should be cleaned up to work nicely with void __iomem * | ||
681 | */ | ||
682 | static u32 omap2_get_clksel(u32 *div_sel, u32 *field_mask, | ||
683 | struct clk *clk) | ||
684 | { | ||
685 | int ret = ~0; | ||
686 | u32 reg_val, div_off; | ||
687 | u32 div_addr = 0; | ||
688 | u32 mask = ~0; | ||
689 | |||
690 | div_off = clk->rate_offset; | ||
691 | |||
692 | switch ((*div_sel & SRC_RATE_SEL_MASK)) { | ||
693 | case CM_MPU_SEL1: | ||
694 | div_addr = (u32)&CM_CLKSEL_MPU; | ||
695 | mask = 0x1f; | ||
696 | break; | ||
697 | case CM_DSP_SEL1: | ||
698 | div_addr = (u32)&CM_CLKSEL_DSP; | ||
699 | if (cpu_is_omap2420()) { | ||
700 | if ((div_off == 0) || (div_off == 8)) | ||
701 | mask = 0x1f; | ||
702 | else if (div_off == 5) | ||
703 | mask = 0x3; | ||
704 | } else if (cpu_is_omap2430()) { | ||
705 | if (div_off == 0) | ||
706 | mask = 0x1f; | ||
707 | else if (div_off == 5) | ||
708 | mask = 0x3; | ||
709 | } | ||
710 | break; | ||
711 | case CM_GFX_SEL1: | ||
712 | div_addr = (u32)&CM_CLKSEL_GFX; | ||
713 | if (div_off == 0) | ||
714 | mask = 0x7; | ||
715 | break; | ||
716 | case CM_MODEM_SEL1: | ||
717 | div_addr = (u32)&CM_CLKSEL_MDM; | ||
718 | if (div_off == 0) | ||
719 | mask = 0xf; | ||
720 | break; | ||
721 | case CM_SYSCLKOUT_SEL1: | ||
722 | div_addr = (u32)&PRCM_CLKOUT_CTRL; | ||
723 | if ((div_off == 3) || (div_off == 11)) | ||
724 | mask= 0x3; | ||
725 | break; | ||
726 | case CM_CORE_SEL1: | ||
727 | div_addr = (u32)&CM_CLKSEL1_CORE; | ||
728 | switch (div_off) { | ||
729 | case 0: /* l3 */ | ||
730 | case 8: /* dss1 */ | ||
731 | case 15: /* vylnc-2420 */ | ||
732 | case 20: /* ssi */ | ||
733 | mask = 0x1f; break; | ||
734 | case 5: /* l4 */ | ||
735 | mask = 0x3; break; | ||
736 | case 13: /* dss2 */ | ||
737 | mask = 0x1; break; | ||
738 | case 25: /* usb */ | ||
739 | mask = 0x7; break; | ||
740 | } | ||
741 | } | ||
742 | |||
743 | *field_mask = mask; | ||
744 | |||
745 | if (unlikely(mask == ~0)) | ||
746 | div_addr = 0; | ||
747 | |||
748 | *div_sel = div_addr; | ||
749 | |||
750 | if (unlikely(div_addr == 0)) | ||
751 | return ret; | ||
752 | |||
753 | /* Isolate field */ | ||
754 | reg_val = __raw_readl((void __iomem *)div_addr) & (mask << div_off); | ||
755 | |||
756 | /* Normalize back to divider value */ | ||
757 | reg_val >>= div_off; | ||
758 | |||
759 | return reg_val; | ||
760 | } | ||
761 | |||
762 | /* | ||
763 | * Return divider to be applied to parent clock. | ||
764 | * Return 0 on error. | ||
765 | */ | ||
766 | static u32 omap2_clksel_get_divisor(struct clk *clk) | ||
767 | { | ||
768 | int ret = 0; | ||
769 | u32 div, div_sel, div_off, field_mask, field_val; | ||
770 | |||
771 | /* isolate control register */ | ||
772 | div_sel = (SRC_RATE_SEL_MASK & clk->flags); | ||
773 | |||
774 | div_off = clk->rate_offset; | ||
775 | field_val = omap2_get_clksel(&div_sel, &field_mask, clk); | ||
776 | if (div_sel == 0) | ||
777 | return ret; | ||
778 | |||
779 | div_sel = (SRC_RATE_SEL_MASK & clk->flags); | ||
780 | div = omap2_clksel_to_divisor(div_sel, field_val); | ||
781 | |||
782 | return div; | ||
783 | } | ||
784 | |||
785 | /* Set the clock rate for a clock source */ | ||
786 | static int omap2_clk_set_rate(struct clk *clk, unsigned long rate) | ||
787 | |||
788 | { | ||
789 | int ret = -EINVAL; | ||
790 | void __iomem * reg; | ||
791 | u32 div_sel, div_off, field_mask, field_val, reg_val, validrate; | ||
792 | u32 new_div = 0; | ||
793 | |||
794 | if (!(clk->flags & CONFIG_PARTICIPANT) && (clk->flags & RATE_CKCTL)) { | ||
795 | if (clk == &dpll_ck) | ||
796 | return omap2_reprogram_dpll(clk, rate); | ||
797 | |||
798 | /* Isolate control register */ | ||
799 | div_sel = (SRC_RATE_SEL_MASK & clk->flags); | ||
800 | div_off = clk->rate_offset; | ||
801 | |||
802 | validrate = omap2_clksel_round_rate(clk, rate, &new_div); | ||
803 | if (validrate != rate) | ||
804 | return(ret); | ||
805 | |||
806 | field_val = omap2_get_clksel(&div_sel, &field_mask, clk); | ||
807 | if (div_sel == 0) | ||
808 | return ret; | ||
809 | |||
810 | if (clk->flags & CM_SYSCLKOUT_SEL1) { | ||
811 | switch (new_div) { | ||
812 | case 16: | ||
813 | field_val = 4; | ||
814 | break; | ||
815 | case 8: | ||
816 | field_val = 3; | ||
817 | break; | ||
818 | case 4: | ||
819 | field_val = 2; | ||
820 | break; | ||
821 | case 2: | ||
822 | field_val = 1; | ||
823 | break; | ||
824 | case 1: | ||
825 | field_val = 0; | ||
826 | break; | ||
827 | } | ||
828 | } else | ||
829 | field_val = new_div; | ||
830 | |||
831 | reg = (void __iomem *)div_sel; | ||
832 | |||
833 | reg_val = __raw_readl(reg); | ||
834 | reg_val &= ~(field_mask << div_off); | ||
835 | reg_val |= (field_val << div_off); | ||
836 | __raw_writel(reg_val, reg); | ||
837 | wmb(); | ||
838 | clk->rate = clk->parent->rate / field_val; | ||
839 | |||
840 | if (clk->flags & DELAYED_APP) { | ||
841 | __raw_writel(0x1, (void __iomem *)&PRCM_CLKCFG_CTRL); | ||
842 | wmb(); | ||
843 | } | ||
844 | ret = 0; | ||
845 | } else if (clk->set_rate != 0) | ||
846 | ret = clk->set_rate(clk, rate); | ||
847 | |||
848 | if (unlikely(ret == 0 && (clk->flags & RATE_PROPAGATES))) | ||
849 | propagate_rate(clk); | ||
850 | |||
851 | return ret; | ||
852 | } | ||
853 | |||
854 | /* Converts encoded control register address into a full address */ | ||
855 | static u32 omap2_get_src_field(u32 *type_to_addr, u32 reg_offset, | ||
856 | struct clk *src_clk, u32 *field_mask) | ||
857 | { | ||
858 | u32 val = ~0, src_reg_addr = 0, mask = 0; | ||
859 | |||
860 | /* Find target control register.*/ | ||
861 | switch ((*type_to_addr & SRC_RATE_SEL_MASK)) { | ||
862 | case CM_CORE_SEL1: | ||
863 | src_reg_addr = (u32)&CM_CLKSEL1_CORE; | ||
864 | if (reg_offset == 13) { /* DSS2_fclk */ | ||
865 | mask = 0x1; | ||
866 | if (src_clk == &sys_ck) | ||
867 | val = 0; | ||
868 | if (src_clk == &func_48m_ck) | ||
869 | val = 1; | ||
870 | } else if (reg_offset == 8) { /* DSS1_fclk */ | ||
871 | mask = 0x1f; | ||
872 | if (src_clk == &sys_ck) | ||
873 | val = 0; | ||
874 | else if (src_clk == &core_ck) /* divided clock */ | ||
875 | val = 0x10; /* rate needs fixing */ | ||
876 | } else if ((reg_offset == 15) && cpu_is_omap2420()){ /*vlnyq*/ | ||
877 | mask = 0x1F; | ||
878 | if(src_clk == &func_96m_ck) | ||
879 | val = 0; | ||
880 | else if (src_clk == &core_ck) | ||
881 | val = 0x10; | ||
882 | } | ||
883 | break; | ||
884 | case CM_CORE_SEL2: | ||
885 | src_reg_addr = (u32)&CM_CLKSEL2_CORE; | ||
886 | mask = 0x3; | ||
887 | if (src_clk == &func_32k_ck) | ||
888 | val = 0x0; | ||
889 | if (src_clk == &sys_ck) | ||
890 | val = 0x1; | ||
891 | if (src_clk == &alt_ck) | ||
892 | val = 0x2; | ||
893 | break; | ||
894 | case CM_WKUP_SEL1: | ||
895 | src_reg_addr = (u32)&CM_CLKSEL_WKUP; | ||
896 | mask = 0x3; | ||
897 | if (src_clk == &func_32k_ck) | ||
898 | val = 0x0; | ||
899 | if (src_clk == &sys_ck) | ||
900 | val = 0x1; | ||
901 | if (src_clk == &alt_ck) | ||
902 | val = 0x2; | ||
903 | break; | ||
904 | case CM_PLL_SEL1: | ||
905 | src_reg_addr = (u32)&CM_CLKSEL1_PLL; | ||
906 | mask = 0x1; | ||
907 | if (reg_offset == 0x3) { | ||
908 | if (src_clk == &apll96_ck) | ||
909 | val = 0; | ||
910 | if (src_clk == &alt_ck) | ||
911 | val = 1; | ||
912 | } | ||
913 | else if (reg_offset == 0x5) { | ||
914 | if (src_clk == &apll54_ck) | ||
915 | val = 0; | ||
916 | if (src_clk == &alt_ck) | ||
917 | val = 1; | ||
918 | } | ||
919 | break; | ||
920 | case CM_PLL_SEL2: | ||
921 | src_reg_addr = (u32)&CM_CLKSEL2_PLL; | ||
922 | mask = 0x3; | ||
923 | if (src_clk == &func_32k_ck) | ||
924 | val = 0x0; | ||
925 | if (src_clk == &dpll_ck) | ||
926 | val = 0x2; | ||
927 | break; | ||
928 | case CM_SYSCLKOUT_SEL1: | ||
929 | src_reg_addr = (u32)&PRCM_CLKOUT_CTRL; | ||
930 | mask = 0x3; | ||
931 | if (src_clk == &dpll_ck) | ||
932 | val = 0; | ||
933 | if (src_clk == &sys_ck) | ||
934 | val = 1; | ||
935 | if (src_clk == &func_96m_ck) | ||
936 | val = 2; | ||
937 | if (src_clk == &func_54m_ck) | ||
938 | val = 3; | ||
939 | break; | ||
940 | } | ||
941 | |||
942 | if (val == ~0) /* Catch errors in offset */ | ||
943 | *type_to_addr = 0; | ||
944 | else | ||
945 | *type_to_addr = src_reg_addr; | ||
946 | *field_mask = mask; | ||
947 | |||
948 | return val; | ||
949 | } | ||
950 | |||
951 | static int omap2_clk_set_parent(struct clk *clk, struct clk *new_parent) | ||
952 | { | ||
953 | void __iomem * reg; | ||
954 | u32 src_sel, src_off, field_val, field_mask, reg_val, rate; | ||
955 | int ret = -EINVAL; | ||
956 | |||
957 | if (unlikely(clk->flags & CONFIG_PARTICIPANT)) | ||
958 | return ret; | ||
959 | |||
960 | if (clk->flags & SRC_SEL_MASK) { /* On-chip SEL collection */ | ||
961 | src_sel = (SRC_RATE_SEL_MASK & clk->flags); | ||
962 | src_off = clk->src_offset; | ||
963 | |||
964 | if (src_sel == 0) | ||
965 | goto set_parent_error; | ||
966 | |||
967 | field_val = omap2_get_src_field(&src_sel, src_off, new_parent, | ||
968 | &field_mask); | ||
969 | |||
970 | reg = (void __iomem *)src_sel; | ||
971 | |||
972 | if (clk->usecount > 0) | ||
973 | _omap2_clk_disable(clk); | ||
974 | |||
975 | /* Set new source value (previous dividers if any in effect) */ | ||
976 | reg_val = __raw_readl(reg) & ~(field_mask << src_off); | ||
977 | reg_val |= (field_val << src_off); | ||
978 | __raw_writel(reg_val, reg); | ||
979 | wmb(); | ||
980 | |||
981 | if (clk->flags & DELAYED_APP) { | ||
982 | __raw_writel(0x1, (void __iomem *)&PRCM_CLKCFG_CTRL); | ||
983 | wmb(); | ||
984 | } | ||
985 | if (clk->usecount > 0) | ||
986 | _omap2_clk_enable(clk); | ||
987 | |||
988 | clk->parent = new_parent; | ||
989 | |||
990 | /* SRC_RATE_SEL_MASK clocks follow their parents rates.*/ | ||
991 | if ((new_parent == &core_ck) && (clk == &dss1_fck)) | ||
992 | clk->rate = new_parent->rate / 0x10; | ||
993 | else | ||
994 | clk->rate = new_parent->rate; | ||
995 | |||
996 | if (unlikely(clk->flags & RATE_PROPAGATES)) | ||
997 | propagate_rate(clk); | ||
998 | |||
999 | return 0; | ||
1000 | } else { | ||
1001 | clk->parent = new_parent; | ||
1002 | rate = new_parent->rate; | ||
1003 | omap2_clk_set_rate(clk, rate); | ||
1004 | ret = 0; | ||
1005 | } | ||
1006 | |||
1007 | set_parent_error: | ||
1008 | return ret; | ||
1009 | } | ||
1010 | #endif /* OLD_CK */ | ||
1011 | |||
1012 | /* Sets basic clocks based on the specified rate */ | 310 | /* Sets basic clocks based on the specified rate */ |
1013 | static int omap2_select_table_rate(struct clk *clk, unsigned long rate) | 311 | static int omap2_select_table_rate(struct clk *clk, unsigned long rate) |
1014 | { | 312 | { |
@@ -1090,26 +388,6 @@ static int omap2_select_table_rate(struct clk *clk, unsigned long rate) | |||
1090 | return 0; | 388 | return 0; |
1091 | } | 389 | } |
1092 | 390 | ||
1093 | /*------------------------------------------------------------------------- | ||
1094 | * Omap2 clock reset and init functions | ||
1095 | *-------------------------------------------------------------------------*/ | ||
1096 | |||
1097 | #ifdef CONFIG_OMAP_RESET_CLOCKS | ||
1098 | static void __init omap2_clk_disable_unused(struct clk *clk) | ||
1099 | { | ||
1100 | u32 regval32; | ||
1101 | |||
1102 | regval32 = __raw_readl(clk->enable_reg); | ||
1103 | if ((regval32 & (1 << clk->enable_bit)) == 0) | ||
1104 | return; | ||
1105 | |||
1106 | printk(KERN_INFO "Disabling unused clock \"%s\"\n", clk->name); | ||
1107 | _omap2_clk_disable(clk); | ||
1108 | } | ||
1109 | #else | ||
1110 | #define omap2_clk_disable_unused NULL | ||
1111 | #endif | ||
1112 | |||
1113 | static struct clk_functions omap2_clk_functions = { | 391 | static struct clk_functions omap2_clk_functions = { |
1114 | .clk_enable = omap2_clk_enable, | 392 | .clk_enable = omap2_clk_enable, |
1115 | .clk_disable = omap2_clk_disable, | 393 | .clk_disable = omap2_clk_disable, |