diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2008-07-14 19:06:58 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2008-07-14 19:06:58 -0400 |
commit | 85082fd7cbe3173198aac0eb5e85ab1edcc6352c (patch) | |
tree | edbc09b7945994f78668d218fa02e991c3b3b365 /arch/arm/mach-omap2/clock.c | |
parent | 666484f0250db2e016948d63b3ef33e202e3b8d0 (diff) | |
parent | 53ffe3b440aa85af6fc4eda09b2d44bcdd312d4d (diff) |
Merge branch 'for-linus' of master.kernel.org:/home/rmk/linux-2.6-arm
* 'for-linus' of master.kernel.org:/home/rmk/linux-2.6-arm: (241 commits)
[ARM] 5171/1: ep93xx: fix compilation of modules using clocks
[ARM] 5133/2: at91sam9g20 defconfig file
[ARM] 5130/4: Support for the at91sam9g20
[ARM] 5160/1: IOP3XX: gpio/gpiolib support
[ARM] at91: Fix NAND FLASH timings for at91sam9x evaluation kits.
[ARM] 5084/1: zylonite: Register AC97 device
[ARM] 5085/2: PXA: Move AC97 over to the new central device declaration model
[ARM] 5120/1: pxa: correct platform driver names for PXA25x and PXA27x UDC drivers
[ARM] 5147/1: pxaficp_ir: drop pxa_gpio_mode calls, as pin setting
[ARM] 5145/1: PXA2xx: provide api to control IrDA pins state
[ARM] 5144/1: pxaficp_ir: cleanup includes
[ARM] pxa: remove pxa_set_cken()
[ARM] pxa: allow clk aliases
[ARM] Feroceon: don't disable BPU on boot
[ARM] Orion: LED support for HP mv2120
[ARM] Orion: add RD88F5181L-FXO support
[ARM] Orion: add RD88F5181L-GE support
[ARM] Orion: add Netgear WNR854T support
[ARM] s3c2410_defconfig: update for current build
[ARM] Acer n30: Minor style and indentation fixes.
...
Diffstat (limited to 'arch/arm/mach-omap2/clock.c')
-rw-r--r-- | arch/arm/mach-omap2/clock.c | 201 |
1 files changed, 199 insertions, 2 deletions
diff --git a/arch/arm/mach-omap2/clock.c b/arch/arm/mach-omap2/clock.c index ab9fc57d25f1..15675bce8012 100644 --- a/arch/arm/mach-omap2/clock.c +++ b/arch/arm/mach-omap2/clock.c | |||
@@ -41,6 +41,24 @@ | |||
41 | 41 | ||
42 | #define MAX_CLOCK_ENABLE_WAIT 100000 | 42 | #define MAX_CLOCK_ENABLE_WAIT 100000 |
43 | 43 | ||
44 | /* DPLL rate rounding: minimum DPLL multiplier, divider values */ | ||
45 | #define DPLL_MIN_MULTIPLIER 1 | ||
46 | #define DPLL_MIN_DIVIDER 1 | ||
47 | |||
48 | /* Possible error results from _dpll_test_mult */ | ||
49 | #define DPLL_MULT_UNDERFLOW (1 << 0) | ||
50 | |||
51 | /* | ||
52 | * Scale factor to mitigate roundoff errors in DPLL rate rounding. | ||
53 | * The higher the scale factor, the greater the risk of arithmetic overflow, | ||
54 | * but the closer the rounded rate to the target rate. DPLL_SCALE_FACTOR | ||
55 | * must be a power of DPLL_SCALE_BASE. | ||
56 | */ | ||
57 | #define DPLL_SCALE_FACTOR 64 | ||
58 | #define DPLL_SCALE_BASE 2 | ||
59 | #define DPLL_ROUNDING_VAL ((DPLL_SCALE_BASE / 2) * \ | ||
60 | (DPLL_SCALE_FACTOR / DPLL_SCALE_BASE)) | ||
61 | |||
44 | u8 cpu_mask; | 62 | u8 cpu_mask; |
45 | 63 | ||
46 | /*------------------------------------------------------------------------- | 64 | /*------------------------------------------------------------------------- |
@@ -95,7 +113,7 @@ u32 omap2_get_dpll_rate(struct clk *clk) | |||
95 | { | 113 | { |
96 | long long dpll_clk; | 114 | long long dpll_clk; |
97 | u32 dpll_mult, dpll_div, dpll; | 115 | u32 dpll_mult, dpll_div, dpll; |
98 | const struct dpll_data *dd; | 116 | struct dpll_data *dd; |
99 | 117 | ||
100 | dd = clk->dpll_data; | 118 | dd = clk->dpll_data; |
101 | /* REVISIT: What do we return on error? */ | 119 | /* REVISIT: What do we return on error? */ |
@@ -603,7 +621,8 @@ int omap2_clksel_set_rate(struct clk *clk, unsigned long rate) | |||
603 | clk->rate = clk->parent->rate / new_div; | 621 | clk->rate = clk->parent->rate / new_div; |
604 | 622 | ||
605 | if (clk->flags & DELAYED_APP && cpu_is_omap24xx()) { | 623 | if (clk->flags & DELAYED_APP && cpu_is_omap24xx()) { |
606 | __raw_writel(OMAP24XX_VALID_CONFIG, OMAP24XX_PRCM_CLKCFG_CTRL); | 624 | prm_write_mod_reg(OMAP24XX_VALID_CONFIG, |
625 | OMAP24XX_GR_MOD, OMAP24XX_PRCM_CLKCFG_CTRL_OFFSET); | ||
607 | wmb(); | 626 | wmb(); |
608 | } | 627 | } |
609 | 628 | ||
@@ -723,6 +742,184 @@ int omap2_clk_set_parent(struct clk *clk, struct clk *new_parent) | |||
723 | return 0; | 742 | return 0; |
724 | } | 743 | } |
725 | 744 | ||
745 | /* DPLL rate rounding code */ | ||
746 | |||
747 | /** | ||
748 | * omap2_dpll_set_rate_tolerance: set the error tolerance during rate rounding | ||
749 | * @clk: struct clk * of the DPLL | ||
750 | * @tolerance: maximum rate error tolerance | ||
751 | * | ||
752 | * Set the maximum DPLL rate error tolerance for the rate rounding | ||
753 | * algorithm. The rate tolerance is an attempt to balance DPLL power | ||
754 | * saving (the least divider value "n") vs. rate fidelity (the least | ||
755 | * difference between the desired DPLL target rate and the rounded | ||
756 | * rate out of the algorithm). So, increasing the tolerance is likely | ||
757 | * to decrease DPLL power consumption and increase DPLL rate error. | ||
758 | * Returns -EINVAL if provided a null clock ptr or a clk that is not a | ||
759 | * DPLL; or 0 upon success. | ||
760 | */ | ||
761 | int omap2_dpll_set_rate_tolerance(struct clk *clk, unsigned int tolerance) | ||
762 | { | ||
763 | if (!clk || !clk->dpll_data) | ||
764 | return -EINVAL; | ||
765 | |||
766 | clk->dpll_data->rate_tolerance = tolerance; | ||
767 | |||
768 | return 0; | ||
769 | } | ||
770 | |||
771 | static unsigned long _dpll_compute_new_rate(unsigned long parent_rate, unsigned int m, unsigned int n) | ||
772 | { | ||
773 | unsigned long long num; | ||
774 | |||
775 | num = (unsigned long long)parent_rate * m; | ||
776 | do_div(num, n); | ||
777 | return num; | ||
778 | } | ||
779 | |||
780 | /* | ||
781 | * _dpll_test_mult - test a DPLL multiplier value | ||
782 | * @m: pointer to the DPLL m (multiplier) value under test | ||
783 | * @n: current DPLL n (divider) value under test | ||
784 | * @new_rate: pointer to storage for the resulting rounded rate | ||
785 | * @target_rate: the desired DPLL rate | ||
786 | * @parent_rate: the DPLL's parent clock rate | ||
787 | * | ||
788 | * This code tests a DPLL multiplier value, ensuring that the | ||
789 | * resulting rate will not be higher than the target_rate, and that | ||
790 | * the multiplier value itself is valid for the DPLL. Initially, the | ||
791 | * integer pointed to by the m argument should be prescaled by | ||
792 | * multiplying by DPLL_SCALE_FACTOR. The code will replace this with | ||
793 | * a non-scaled m upon return. This non-scaled m will result in a | ||
794 | * new_rate as close as possible to target_rate (but not greater than | ||
795 | * target_rate) given the current (parent_rate, n, prescaled m) | ||
796 | * triple. Returns DPLL_MULT_UNDERFLOW in the event that the | ||
797 | * non-scaled m attempted to underflow, which can allow the calling | ||
798 | * function to bail out early; or 0 upon success. | ||
799 | */ | ||
800 | static int _dpll_test_mult(int *m, int n, unsigned long *new_rate, | ||
801 | unsigned long target_rate, | ||
802 | unsigned long parent_rate) | ||
803 | { | ||
804 | int flags = 0, carry = 0; | ||
805 | |||
806 | /* Unscale m and round if necessary */ | ||
807 | if (*m % DPLL_SCALE_FACTOR >= DPLL_ROUNDING_VAL) | ||
808 | carry = 1; | ||
809 | *m = (*m / DPLL_SCALE_FACTOR) + carry; | ||
810 | |||
811 | /* | ||
812 | * The new rate must be <= the target rate to avoid programming | ||
813 | * a rate that is impossible for the hardware to handle | ||
814 | */ | ||
815 | *new_rate = _dpll_compute_new_rate(parent_rate, *m, n); | ||
816 | if (*new_rate > target_rate) { | ||
817 | (*m)--; | ||
818 | *new_rate = 0; | ||
819 | } | ||
820 | |||
821 | /* Guard against m underflow */ | ||
822 | if (*m < DPLL_MIN_MULTIPLIER) { | ||
823 | *m = DPLL_MIN_MULTIPLIER; | ||
824 | *new_rate = 0; | ||
825 | flags = DPLL_MULT_UNDERFLOW; | ||
826 | } | ||
827 | |||
828 | if (*new_rate == 0) | ||
829 | *new_rate = _dpll_compute_new_rate(parent_rate, *m, n); | ||
830 | |||
831 | return flags; | ||
832 | } | ||
833 | |||
834 | /** | ||
835 | * omap2_dpll_round_rate - round a target rate for an OMAP DPLL | ||
836 | * @clk: struct clk * for a DPLL | ||
837 | * @target_rate: desired DPLL clock rate | ||
838 | * | ||
839 | * Given a DPLL, a desired target rate, and a rate tolerance, round | ||
840 | * the target rate to a possible, programmable rate for this DPLL. | ||
841 | * Rate tolerance is assumed to be set by the caller before this | ||
842 | * function is called. Attempts to select the minimum possible n | ||
843 | * within the tolerance to reduce power consumption. Stores the | ||
844 | * computed (m, n) in the DPLL's dpll_data structure so set_rate() | ||
845 | * will not need to call this (expensive) function again. Returns ~0 | ||
846 | * if the target rate cannot be rounded, either because the rate is | ||
847 | * too low or because the rate tolerance is set too tightly; or the | ||
848 | * rounded rate upon success. | ||
849 | */ | ||
850 | long omap2_dpll_round_rate(struct clk *clk, unsigned long target_rate) | ||
851 | { | ||
852 | int m, n, r, e, scaled_max_m; | ||
853 | unsigned long scaled_rt_rp, new_rate; | ||
854 | int min_e = -1, min_e_m = -1, min_e_n = -1; | ||
855 | |||
856 | if (!clk || !clk->dpll_data) | ||
857 | return ~0; | ||
858 | |||
859 | pr_debug("clock: starting DPLL round_rate for clock %s, target rate " | ||
860 | "%ld\n", clk->name, target_rate); | ||
861 | |||
862 | scaled_rt_rp = target_rate / (clk->parent->rate / DPLL_SCALE_FACTOR); | ||
863 | scaled_max_m = clk->dpll_data->max_multiplier * DPLL_SCALE_FACTOR; | ||
864 | |||
865 | clk->dpll_data->last_rounded_rate = 0; | ||
866 | |||
867 | for (n = clk->dpll_data->max_divider; n >= DPLL_MIN_DIVIDER; n--) { | ||
868 | |||
869 | /* Compute the scaled DPLL multiplier, based on the divider */ | ||
870 | m = scaled_rt_rp * n; | ||
871 | |||
872 | /* | ||
873 | * Since we're counting n down, a m overflow means we can | ||
874 | * can immediately skip to the next n | ||
875 | */ | ||
876 | if (m > scaled_max_m) | ||
877 | continue; | ||
878 | |||
879 | r = _dpll_test_mult(&m, n, &new_rate, target_rate, | ||
880 | clk->parent->rate); | ||
881 | |||
882 | e = target_rate - new_rate; | ||
883 | pr_debug("clock: n = %d: m = %d: rate error is %d " | ||
884 | "(new_rate = %ld)\n", n, m, e, new_rate); | ||
885 | |||
886 | if (min_e == -1 || | ||
887 | min_e >= (int)(abs(e) - clk->dpll_data->rate_tolerance)) { | ||
888 | min_e = e; | ||
889 | min_e_m = m; | ||
890 | min_e_n = n; | ||
891 | |||
892 | pr_debug("clock: found new least error %d\n", min_e); | ||
893 | } | ||
894 | |||
895 | /* | ||
896 | * Since we're counting n down, a m underflow means we | ||
897 | * can bail out completely (since as n decreases in | ||
898 | * the next iteration, there's no way that m can | ||
899 | * increase beyond the current m) | ||
900 | */ | ||
901 | if (r & DPLL_MULT_UNDERFLOW) | ||
902 | break; | ||
903 | } | ||
904 | |||
905 | if (min_e < 0) { | ||
906 | pr_debug("clock: error: target rate or tolerance too low\n"); | ||
907 | return ~0; | ||
908 | } | ||
909 | |||
910 | clk->dpll_data->last_rounded_m = min_e_m; | ||
911 | clk->dpll_data->last_rounded_n = min_e_n; | ||
912 | clk->dpll_data->last_rounded_rate = | ||
913 | _dpll_compute_new_rate(clk->parent->rate, min_e_m, min_e_n); | ||
914 | |||
915 | pr_debug("clock: final least error: e = %d, m = %d, n = %d\n", | ||
916 | min_e, min_e_m, min_e_n); | ||
917 | pr_debug("clock: final rate: %ld (target rate: %ld)\n", | ||
918 | clk->dpll_data->last_rounded_rate, target_rate); | ||
919 | |||
920 | return clk->dpll_data->last_rounded_rate; | ||
921 | } | ||
922 | |||
726 | /*------------------------------------------------------------------------- | 923 | /*------------------------------------------------------------------------- |
727 | * Omap2 clock reset and init functions | 924 | * Omap2 clock reset and init functions |
728 | *-------------------------------------------------------------------------*/ | 925 | *-------------------------------------------------------------------------*/ |