aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPaul Walmsley <paul@pwsan.com>2009-01-28 14:08:44 -0500
committerRussell King <rmk+kernel@arm.linux.org.uk>2009-02-08 12:50:35 -0500
commit95f538ac370d9625457ba00ef7c3bb91e2b92f89 (patch)
tree3fff982958af2674f57a200ff26619e32135f95c
parent85a5f78d2b15a2e73b6486a24b77bb3ab67d5bbc (diff)
[ARM] OMAP3 clock: avoid invalid FREQSEL values during DPLL rate rounding
The DPLL FREQSEL jitter correction bits are set based on a table in the 34xx TRM, Table 4-38, according to the DPLL's internal clock frequency "Fint." Several Fint frequency ranges are missing from this table. Previously, we allowed these Fint frequency ranges to be selected in the rate rounding code, but did not change the FREQSEL bits. Correspondence with the OMAP hardware team indicates that Fint values not in the table should not be used. So, prevent them from being selected during DPLL rate rounding. This removes warnings and also can prevent the chip from locking up. The first pass through the rate rounding code will update the DPLL max and min dividers appropriately, so later rate rounding passes will run faster than the first. Peter de Schrijver <peter.de-schrijver@nokia.com> put up with several test cycles of this patch - thanks Peter. linux-omap source commit is f9c1b82f55b60fc39eaa6e7aa1fbe380c0ffe2e9. Signed-off-by: Paul Walmsley <paul@pwsan.com> Cc: Peter de Schrijver <peter.de-schrijver@nokia.com> Signed-off-by: Tony Lindgren <tony@atomide.com> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
-rw-r--r--arch/arm/mach-omap2/clock.c67
-rw-r--r--arch/arm/mach-omap2/clock24xx.h1
-rw-r--r--arch/arm/mach-omap2/clock34xx.h5
-rw-r--r--arch/arm/plat-omap/include/mach/clock.h1
4 files changed, 72 insertions, 2 deletions
diff --git a/arch/arm/mach-omap2/clock.c b/arch/arm/mach-omap2/clock.c
index 76e20bcc4e8a..752e34787f21 100644
--- a/arch/arm/mach-omap2/clock.c
+++ b/arch/arm/mach-omap2/clock.c
@@ -58,12 +58,68 @@
58#define DPLL_ROUNDING_VAL ((DPLL_SCALE_BASE / 2) * \ 58#define DPLL_ROUNDING_VAL ((DPLL_SCALE_BASE / 2) * \
59 (DPLL_SCALE_FACTOR / DPLL_SCALE_BASE)) 59 (DPLL_SCALE_FACTOR / DPLL_SCALE_BASE))
60 60
61/* DPLL valid Fint frequency band limits - from 34xx TRM Section 4.7.6.2 */
62#define DPLL_FINT_BAND1_MIN 750000
63#define DPLL_FINT_BAND1_MAX 2100000
64#define DPLL_FINT_BAND2_MIN 7500000
65#define DPLL_FINT_BAND2_MAX 21000000
66
67/* _dpll_test_fint() return codes */
68#define DPLL_FINT_UNDERFLOW -1
69#define DPLL_FINT_INVALID -2
70
61u8 cpu_mask; 71u8 cpu_mask;
62 72
63/*------------------------------------------------------------------------- 73/*-------------------------------------------------------------------------
64 * OMAP2/3 specific clock functions 74 * OMAP2/3 specific clock functions
65 *-------------------------------------------------------------------------*/ 75 *-------------------------------------------------------------------------*/
66 76
77/*
78 * _dpll_test_fint - test whether an Fint value is valid for the DPLL
79 * @clk: DPLL struct clk to test
80 * @n: divider value (N) to test
81 *
82 * Tests whether a particular divider @n will result in a valid DPLL
83 * internal clock frequency Fint. See the 34xx TRM 4.7.6.2 "DPLL Jitter
84 * Correction". Returns 0 if OK, -1 if the enclosing loop can terminate
85 * (assuming that it is counting N upwards), or -2 if the enclosing loop
86 * should skip to the next iteration (again assuming N is increasing).
87 */
88static int _dpll_test_fint(struct clk *clk, u8 n)
89{
90 struct dpll_data *dd;
91 long fint;
92 int ret = 0;
93
94 dd = clk->dpll_data;
95
96 /* DPLL divider must result in a valid jitter correction val */
97 fint = clk->parent->rate / (n + 1);
98 if (fint < DPLL_FINT_BAND1_MIN) {
99
100 pr_debug("rejecting n=%d due to Fint failure, "
101 "lowering max_divider\n", n);
102 dd->max_divider = n;
103 ret = DPLL_FINT_UNDERFLOW;
104
105 } else if (fint > DPLL_FINT_BAND1_MAX &&
106 fint < DPLL_FINT_BAND2_MIN) {
107
108 pr_debug("rejecting n=%d due to Fint failure\n", n);
109 ret = DPLL_FINT_INVALID;
110
111 } else if (fint > DPLL_FINT_BAND2_MAX) {
112
113 pr_debug("rejecting n=%d due to Fint failure, "
114 "boosting min_divider\n", n);
115 dd->min_divider = n;
116 ret = DPLL_FINT_INVALID;
117
118 }
119
120 return ret;
121}
122
67/** 123/**
68 * omap2_init_clk_clkdm - look up a clockdomain name, store pointer in clk 124 * omap2_init_clk_clkdm - look up a clockdomain name, store pointer in clk
69 * @clk: OMAP clock struct ptr to use 125 * @clk: OMAP clock struct ptr to use
@@ -892,7 +948,14 @@ long omap2_dpll_round_rate(struct clk *clk, unsigned long target_rate)
892 948
893 dd->last_rounded_rate = 0; 949 dd->last_rounded_rate = 0;
894 950
895 for (n = DPLL_MIN_DIVIDER; n <= dd->max_divider; n++) { 951 for (n = dd->min_divider; n <= dd->max_divider; n++) {
952
953 /* Is the (input clk, divider) pair valid for the DPLL? */
954 r = _dpll_test_fint(clk, n);
955 if (r == DPLL_FINT_UNDERFLOW)
956 break;
957 else if (r == DPLL_FINT_INVALID)
958 continue;
896 959
897 /* Compute the scaled DPLL multiplier, based on the divider */ 960 /* Compute the scaled DPLL multiplier, based on the divider */
898 m = scaled_rt_rp * n; 961 m = scaled_rt_rp * n;
@@ -926,7 +989,7 @@ long omap2_dpll_round_rate(struct clk *clk, unsigned long target_rate)
926 pr_debug("clock: found new least error %d\n", min_e); 989 pr_debug("clock: found new least error %d\n", min_e);
927 990
928 /* We found good settings -- bail out now */ 991 /* We found good settings -- bail out now */
929 if (min_e <= clk->dpll_data->rate_tolerance) 992 if (min_e <= dd->rate_tolerance)
930 break; 993 break;
931 } 994 }
932 } 995 }
diff --git a/arch/arm/mach-omap2/clock24xx.h b/arch/arm/mach-omap2/clock24xx.h
index 32dd8573e56b..7731ab6acd18 100644
--- a/arch/arm/mach-omap2/clock24xx.h
+++ b/arch/arm/mach-omap2/clock24xx.h
@@ -666,6 +666,7 @@ static struct dpll_data dpll_dd = {
666 .mult_mask = OMAP24XX_DPLL_MULT_MASK, 666 .mult_mask = OMAP24XX_DPLL_MULT_MASK,
667 .div1_mask = OMAP24XX_DPLL_DIV_MASK, 667 .div1_mask = OMAP24XX_DPLL_DIV_MASK,
668 .max_multiplier = 1024, 668 .max_multiplier = 1024,
669 .min_divider = 1,
669 .max_divider = 16, 670 .max_divider = 16,
670 .rate_tolerance = DEFAULT_DPLL_RATE_TOLERANCE 671 .rate_tolerance = DEFAULT_DPLL_RATE_TOLERANCE
671}; 672};
diff --git a/arch/arm/mach-omap2/clock34xx.h b/arch/arm/mach-omap2/clock34xx.h
index 7ee131202625..aadd296c05a2 100644
--- a/arch/arm/mach-omap2/clock34xx.h
+++ b/arch/arm/mach-omap2/clock34xx.h
@@ -268,6 +268,7 @@ static struct dpll_data dpll1_dd = {
268 .idlest_reg = OMAP_CM_REGADDR(MPU_MOD, OMAP3430_CM_IDLEST_PLL), 268 .idlest_reg = OMAP_CM_REGADDR(MPU_MOD, OMAP3430_CM_IDLEST_PLL),
269 .idlest_mask = OMAP3430_ST_MPU_CLK_MASK, 269 .idlest_mask = OMAP3430_ST_MPU_CLK_MASK,
270 .max_multiplier = OMAP3_MAX_DPLL_MULT, 270 .max_multiplier = OMAP3_MAX_DPLL_MULT,
271 .min_divider = 1,
271 .max_divider = OMAP3_MAX_DPLL_DIV, 272 .max_divider = OMAP3_MAX_DPLL_DIV,
272 .rate_tolerance = DEFAULT_DPLL_RATE_TOLERANCE 273 .rate_tolerance = DEFAULT_DPLL_RATE_TOLERANCE
273}; 274};
@@ -341,6 +342,7 @@ static struct dpll_data dpll2_dd = {
341 .idlest_reg = OMAP_CM_REGADDR(OMAP3430_IVA2_MOD, OMAP3430_CM_IDLEST_PLL), 342 .idlest_reg = OMAP_CM_REGADDR(OMAP3430_IVA2_MOD, OMAP3430_CM_IDLEST_PLL),
342 .idlest_mask = OMAP3430_ST_IVA2_CLK_MASK, 343 .idlest_mask = OMAP3430_ST_IVA2_CLK_MASK,
343 .max_multiplier = OMAP3_MAX_DPLL_MULT, 344 .max_multiplier = OMAP3_MAX_DPLL_MULT,
345 .min_divider = 1,
344 .max_divider = OMAP3_MAX_DPLL_DIV, 346 .max_divider = OMAP3_MAX_DPLL_DIV,
345 .rate_tolerance = DEFAULT_DPLL_RATE_TOLERANCE 347 .rate_tolerance = DEFAULT_DPLL_RATE_TOLERANCE
346}; 348};
@@ -400,6 +402,7 @@ static struct dpll_data dpll3_dd = {
400 .idlest_reg = OMAP_CM_REGADDR(PLL_MOD, CM_IDLEST), 402 .idlest_reg = OMAP_CM_REGADDR(PLL_MOD, CM_IDLEST),
401 .idlest_mask = OMAP3430_ST_CORE_CLK_MASK, 403 .idlest_mask = OMAP3430_ST_CORE_CLK_MASK,
402 .max_multiplier = OMAP3_MAX_DPLL_MULT, 404 .max_multiplier = OMAP3_MAX_DPLL_MULT,
405 .min_divider = 1,
403 .max_divider = OMAP3_MAX_DPLL_DIV, 406 .max_divider = OMAP3_MAX_DPLL_DIV,
404 .rate_tolerance = DEFAULT_DPLL_RATE_TOLERANCE 407 .rate_tolerance = DEFAULT_DPLL_RATE_TOLERANCE
405}; 408};
@@ -591,6 +594,7 @@ static struct dpll_data dpll4_dd = {
591 .idlest_reg = OMAP_CM_REGADDR(PLL_MOD, CM_IDLEST), 594 .idlest_reg = OMAP_CM_REGADDR(PLL_MOD, CM_IDLEST),
592 .idlest_mask = OMAP3430_ST_PERIPH_CLK_MASK, 595 .idlest_mask = OMAP3430_ST_PERIPH_CLK_MASK,
593 .max_multiplier = OMAP3_MAX_DPLL_MULT, 596 .max_multiplier = OMAP3_MAX_DPLL_MULT,
597 .min_divider = 1,
594 .max_divider = OMAP3_MAX_DPLL_DIV, 598 .max_divider = OMAP3_MAX_DPLL_DIV,
595 .rate_tolerance = DEFAULT_DPLL_RATE_TOLERANCE 599 .rate_tolerance = DEFAULT_DPLL_RATE_TOLERANCE
596}; 600};
@@ -930,6 +934,7 @@ static struct dpll_data dpll5_dd = {
930 .idlest_reg = OMAP_CM_REGADDR(PLL_MOD, CM_IDLEST2), 934 .idlest_reg = OMAP_CM_REGADDR(PLL_MOD, CM_IDLEST2),
931 .idlest_mask = OMAP3430ES2_ST_PERIPH2_CLK_MASK, 935 .idlest_mask = OMAP3430ES2_ST_PERIPH2_CLK_MASK,
932 .max_multiplier = OMAP3_MAX_DPLL_MULT, 936 .max_multiplier = OMAP3_MAX_DPLL_MULT,
937 .min_divider = 1,
933 .max_divider = OMAP3_MAX_DPLL_DIV, 938 .max_divider = OMAP3_MAX_DPLL_DIV,
934 .rate_tolerance = DEFAULT_DPLL_RATE_TOLERANCE 939 .rate_tolerance = DEFAULT_DPLL_RATE_TOLERANCE
935}; 940};
diff --git a/arch/arm/plat-omap/include/mach/clock.h b/arch/arm/plat-omap/include/mach/clock.h
index 611df52a3242..cd69111cd33f 100644
--- a/arch/arm/plat-omap/include/mach/clock.h
+++ b/arch/arm/plat-omap/include/mach/clock.h
@@ -43,6 +43,7 @@ struct dpll_data {
43 unsigned long last_rounded_rate; 43 unsigned long last_rounded_rate;
44 u16 last_rounded_m; 44 u16 last_rounded_m;
45 u8 last_rounded_n; 45 u8 last_rounded_n;
46 u8 min_divider;
46 u8 max_divider; 47 u8 max_divider;
47 u32 max_tolerance; 48 u32 max_tolerance;
48 u16 max_multiplier; 49 u16 max_multiplier;