diff options
author | Paul Walmsley <paul@pwsan.com> | 2009-01-27 21:12:47 -0500 |
---|---|---|
committer | Russell King <rmk+kernel@arm.linux.org.uk> | 2009-02-08 12:50:24 -0500 |
commit | 16c90f020034d3cd38b3dab280001e728e6b19e5 (patch) | |
tree | 71b142bdf83578688b4844b0b65414f2b3d6c3df /arch/arm/mach-omap2/clock34xx.c | |
parent | 6f7607ccd175518a3ee7dccc1620f3a086689668 (diff) |
[ARM] OMAP2/3: Add non-CORE DPLL rate set code and M, N programming
Add non-CORE DPLL rate set code and M,N programming for OMAP3.
Connect it to OMAP34xx DPLLs 1, 2, 4, 5 via the clock framework.
You may see some warnings on rate sets from the freqsel code. The
table that TI presented in the 3430 TRM Rev F does not cover Fint <
750000, which definitely occurs in practice. However, the lack of this
freqsel case does not appear to impair the DPLL rate change.
linux-omap source commit is 689fe67c6d1ad8f52f7f7b139a3274b79bf3e784.
Signed-off-by: Paul Walmsley <paul@pwsan.com>
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-omap2/clock34xx.c')
-rw-r--r-- | arch/arm/mach-omap2/clock34xx.c | 137 |
1 files changed, 136 insertions, 1 deletions
diff --git a/arch/arm/mach-omap2/clock34xx.c b/arch/arm/mach-omap2/clock34xx.c index 245a7b9b560c..943ac63fc6f8 100644 --- a/arch/arm/mach-omap2/clock34xx.c +++ b/arch/arm/mach-omap2/clock34xx.c | |||
@@ -340,6 +340,42 @@ static int _omap3_wait_dpll_status(struct clk *clk, u8 state) | |||
340 | return ret; | 340 | return ret; |
341 | } | 341 | } |
342 | 342 | ||
343 | /* From 3430 TRM ES2 4.7.6.2 */ | ||
344 | static u16 _omap3_dpll_compute_freqsel(struct clk *clk, u8 n) | ||
345 | { | ||
346 | unsigned long fint; | ||
347 | u16 f = 0; | ||
348 | |||
349 | fint = clk->parent->rate / (n + 1); | ||
350 | |||
351 | pr_debug("clock: fint is %lu\n", fint); | ||
352 | |||
353 | if (fint >= 750000 && fint <= 1000000) | ||
354 | f = 0x3; | ||
355 | else if (fint > 1000000 && fint <= 1250000) | ||
356 | f = 0x4; | ||
357 | else if (fint > 1250000 && fint <= 1500000) | ||
358 | f = 0x5; | ||
359 | else if (fint > 1500000 && fint <= 1750000) | ||
360 | f = 0x6; | ||
361 | else if (fint > 1750000 && fint <= 2100000) | ||
362 | f = 0x7; | ||
363 | else if (fint > 7500000 && fint <= 10000000) | ||
364 | f = 0xB; | ||
365 | else if (fint > 10000000 && fint <= 12500000) | ||
366 | f = 0xC; | ||
367 | else if (fint > 12500000 && fint <= 15000000) | ||
368 | f = 0xD; | ||
369 | else if (fint > 15000000 && fint <= 17500000) | ||
370 | f = 0xE; | ||
371 | else if (fint > 17500000 && fint <= 21000000) | ||
372 | f = 0xF; | ||
373 | else | ||
374 | pr_debug("clock: unknown freqsel setting for %d\n", n); | ||
375 | |||
376 | return f; | ||
377 | } | ||
378 | |||
343 | /* Non-CORE DPLL (e.g., DPLLs that do not control SDRC) clock functions */ | 379 | /* Non-CORE DPLL (e.g., DPLLs that do not control SDRC) clock functions */ |
344 | 380 | ||
345 | /* | 381 | /* |
@@ -476,7 +512,7 @@ static int omap3_noncore_dpll_enable(struct clk *clk) | |||
476 | if (clk == &dpll3_ck) | 512 | if (clk == &dpll3_ck) |
477 | return -EINVAL; | 513 | return -EINVAL; |
478 | 514 | ||
479 | if (clk->parent->rate == clk_get_rate(clk)) | 515 | if (clk->parent->rate == omap2_get_dpll_rate(clk)) |
480 | r = _omap3_noncore_dpll_bypass(clk); | 516 | r = _omap3_noncore_dpll_bypass(clk); |
481 | else | 517 | else |
482 | r = _omap3_noncore_dpll_lock(clk); | 518 | r = _omap3_noncore_dpll_lock(clk); |
@@ -506,11 +542,110 @@ static void omap3_noncore_dpll_disable(struct clk *clk) | |||
506 | _omap3_noncore_dpll_stop(clk); | 542 | _omap3_noncore_dpll_stop(clk); |
507 | } | 543 | } |
508 | 544 | ||
545 | |||
546 | /* Non-CORE DPLL rate set code */ | ||
547 | |||
548 | /* | ||
549 | * omap3_noncore_dpll_program - set non-core DPLL M,N values directly | ||
550 | * @clk: struct clk * of DPLL to set | ||
551 | * @m: DPLL multiplier to set | ||
552 | * @n: DPLL divider to set | ||
553 | * @freqsel: FREQSEL value to set | ||
554 | * | ||
555 | * Program the DPLL with the supplied M, N values, and wait for the DPLL to | ||
556 | * lock.. Returns -EINVAL upon error, or 0 upon success. | ||
557 | */ | ||
558 | static int omap3_noncore_dpll_program(struct clk *clk, u16 m, u8 n, u16 freqsel) | ||
559 | { | ||
560 | struct dpll_data *dd = clk->dpll_data; | ||
561 | u32 v; | ||
562 | |||
563 | /* 3430 ES2 TRM: 4.7.6.9 DPLL Programming Sequence */ | ||
564 | _omap3_noncore_dpll_bypass(clk); | ||
565 | |||
566 | v = __raw_readl(dd->mult_div1_reg); | ||
567 | v &= ~(dd->mult_mask | dd->div1_mask); | ||
568 | |||
569 | /* Set mult (M), div1 (N), freqsel */ | ||
570 | v |= m << __ffs(dd->mult_mask); | ||
571 | v |= n << __ffs(dd->div1_mask); | ||
572 | v |= freqsel << __ffs(dd->freqsel_mask); | ||
573 | |||
574 | __raw_writel(v, dd->mult_div1_reg); | ||
575 | |||
576 | /* We let the clock framework set the other output dividers later */ | ||
577 | |||
578 | /* REVISIT: Set ramp-up delay? */ | ||
579 | |||
580 | _omap3_noncore_dpll_lock(clk); | ||
581 | |||
582 | return 0; | ||
583 | } | ||
584 | |||
585 | /** | ||
586 | * omap3_noncore_dpll_set_rate - set non-core DPLL rate | ||
587 | * @clk: struct clk * of DPLL to set | ||
588 | * @rate: rounded target rate | ||
589 | * | ||
590 | * Program the DPLL with the rounded target rate. Returns -EINVAL upon | ||
591 | * error, or 0 upon success. | ||
592 | */ | ||
593 | static int omap3_noncore_dpll_set_rate(struct clk *clk, unsigned long rate) | ||
594 | { | ||
595 | u16 freqsel; | ||
596 | struct dpll_data *dd; | ||
597 | |||
598 | if (!clk || !rate) | ||
599 | return -EINVAL; | ||
600 | |||
601 | dd = clk->dpll_data; | ||
602 | if (!dd) | ||
603 | return -EINVAL; | ||
604 | |||
605 | if (rate == omap2_get_dpll_rate(clk)) | ||
606 | return 0; | ||
607 | |||
608 | if (dd->last_rounded_rate != rate) | ||
609 | omap2_dpll_round_rate(clk, rate); | ||
610 | |||
611 | if (dd->last_rounded_rate == 0) | ||
612 | return -EINVAL; | ||
613 | |||
614 | freqsel = _omap3_dpll_compute_freqsel(clk, dd->last_rounded_n); | ||
615 | if (!freqsel) | ||
616 | WARN_ON(1); | ||
617 | |||
618 | omap3_noncore_dpll_program(clk, dd->last_rounded_m, dd->last_rounded_n, | ||
619 | freqsel); | ||
620 | |||
621 | omap3_dpll_recalc(clk); | ||
622 | |||
623 | return 0; | ||
624 | } | ||
625 | |||
626 | static int omap3_dpll4_set_rate(struct clk *clk, unsigned long rate) | ||
627 | { | ||
628 | /* | ||
629 | * According to the 12-5 CDP code from TI, "Limitation 2.5" | ||
630 | * on 3430ES1 prevents us from changing DPLL multipliers or dividers | ||
631 | * on DPLL4. | ||
632 | */ | ||
633 | if (omap_rev() == OMAP3430_REV_ES1_0) { | ||
634 | printk(KERN_ERR "clock: DPLL4 cannot change rate due to " | ||
635 | "silicon 'Limitation 2.5' on 3430ES1.\n"); | ||
636 | return -EINVAL; | ||
637 | } | ||
638 | return omap3_noncore_dpll_set_rate(clk, rate); | ||
639 | } | ||
640 | |||
509 | static const struct clkops clkops_noncore_dpll_ops = { | 641 | static const struct clkops clkops_noncore_dpll_ops = { |
510 | .enable = &omap3_noncore_dpll_enable, | 642 | .enable = &omap3_noncore_dpll_enable, |
511 | .disable = &omap3_noncore_dpll_disable, | 643 | .disable = &omap3_noncore_dpll_disable, |
512 | }; | 644 | }; |
513 | 645 | ||
646 | /* DPLL autoidle read/set code */ | ||
647 | |||
648 | |||
514 | /** | 649 | /** |
515 | * omap3_dpll_autoidle_read - read a DPLL's autoidle bits | 650 | * omap3_dpll_autoidle_read - read a DPLL's autoidle bits |
516 | * @clk: struct clk * of the DPLL to read | 651 | * @clk: struct clk * of the DPLL to read |