diff options
author | Paul Walmsley <paul@pwsan.com> | 2010-01-26 22:13:06 -0500 |
---|---|---|
committer | Paul Walmsley <paul@pwsan.com> | 2010-01-26 22:13:06 -0500 |
commit | b1823d8616b11477e9e0967c727ed5325fb12403 (patch) | |
tree | fed4e107c952fa020cb603982977952e50587499 /arch | |
parent | 69ecefca514c318d0ce993c48ffa3bad009c7b9b (diff) |
OMAP2xxx clock: move the DPLL+CORE composite clock code into mach-omap2/clkt2xxx_dpllcore.c
Move the DPLL+CORE composite clock functions from clock2xxx.c to
mach-omap2/clkt2xxx_dpllcore.c. This is intended to make the clock
code easier to understand, since all of the functions needed to manage
the OMAP2 DPLL+CORE clock are now located in their own file, rather
than being mixed with other, unrelated functions.
Clock debugging is also now more finely-grained, since the DEBUG
macro can now be defined for the DPLL+CORE clock alone. This
should reduce unnecessary console noise when debugging.
Also, if at some future point the mach-omap2/ directory is split
into OMAP2/3/4 variants, this clkt file can be placed in the mach-omap2xxx/
directory, rather than shared with other chip types that don't use this
clock type.
Thanks to Alexander Shishkin <virtuoso@slind.org> for his comments to
improve the patch description.
Signed-off-by: Paul Walmsley <paul@pwsan.com>
Cc: Richard Woodruff <r-woodruff2@ti.com>
Cc: Alexander Shishkin <virtuoso@slind.org>
Diffstat (limited to 'arch')
-rw-r--r-- | arch/arm/mach-omap2/Makefile | 4 | ||||
-rw-r--r-- | arch/arm/mach-omap2/clkt2xxx_dpllcore.c | 173 | ||||
-rw-r--r-- | arch/arm/mach-omap2/clock2xxx.c | 136 |
3 files changed, 176 insertions, 137 deletions
diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile index 9ecc58d2c986..04ce372bb105 100644 --- a/arch/arm/mach-omap2/Makefile +++ b/arch/arm/mach-omap2/Makefile | |||
@@ -11,8 +11,10 @@ prcm-common = prcm.o powerdomain.o | |||
11 | clock-common = clock.o clock_common_data.o \ | 11 | clock-common = clock.o clock_common_data.o \ |
12 | clockdomain.o clkt_dpll.o \ | 12 | clockdomain.o clkt_dpll.o \ |
13 | clkt_clksel.o | 13 | clkt_clksel.o |
14 | clock-omap2xxx = clkt2xxx_dpllcore.o | ||
14 | 15 | ||
15 | obj-$(CONFIG_ARCH_OMAP2) += $(omap-2-3-common) $(prcm-common) $(clock-common) | 16 | obj-$(CONFIG_ARCH_OMAP2) += $(omap-2-3-common) $(prcm-common) $(clock-common) \ |
17 | $(clock-omap2xxx) | ||
16 | obj-$(CONFIG_ARCH_OMAP3) += $(omap-2-3-common) $(prcm-common) $(clock-common) \ | 18 | obj-$(CONFIG_ARCH_OMAP3) += $(omap-2-3-common) $(prcm-common) $(clock-common) \ |
17 | $(omap-3-4-common) | 19 | $(omap-3-4-common) |
18 | obj-$(CONFIG_ARCH_OMAP4) += $(omap-3-4-common) $(prcm-common) $(clock-common) | 20 | obj-$(CONFIG_ARCH_OMAP4) += $(omap-3-4-common) $(prcm-common) $(clock-common) |
diff --git a/arch/arm/mach-omap2/clkt2xxx_dpllcore.c b/arch/arm/mach-omap2/clkt2xxx_dpllcore.c new file mode 100644 index 000000000000..019048434f13 --- /dev/null +++ b/arch/arm/mach-omap2/clkt2xxx_dpllcore.c | |||
@@ -0,0 +1,173 @@ | |||
1 | /* | ||
2 | * DPLL + CORE_CLK composite clock functions | ||
3 | * | ||
4 | * Copyright (C) 2005-2008 Texas Instruments, Inc. | ||
5 | * Copyright (C) 2004-2010 Nokia Corporation | ||
6 | * | ||
7 | * Contacts: | ||
8 | * Richard Woodruff <r-woodruff2@ti.com> | ||
9 | * Paul Walmsley | ||
10 | * | ||
11 | * Based on earlier work by Tuukka Tikkanen, Tony Lindgren, | ||
12 | * Gordon McNutt and RidgeRun, Inc. | ||
13 | * | ||
14 | * This program is free software; you can redistribute it and/or modify | ||
15 | * it under the terms of the GNU General Public License version 2 as | ||
16 | * published by the Free Software Foundation. | ||
17 | * | ||
18 | * XXX The DPLL and CORE clocks should be split into two separate clock | ||
19 | * types. | ||
20 | */ | ||
21 | #undef DEBUG | ||
22 | |||
23 | #include <linux/kernel.h> | ||
24 | #include <linux/errno.h> | ||
25 | #include <linux/clk.h> | ||
26 | #include <linux/io.h> | ||
27 | |||
28 | #include <plat/clock.h> | ||
29 | #include <plat/sram.h> | ||
30 | #include <plat/sdrc.h> | ||
31 | |||
32 | #include "clock.h" | ||
33 | #include "clock2xxx.h" | ||
34 | #include "opp2xxx.h" | ||
35 | #include "cm.h" | ||
36 | #include "cm-regbits-24xx.h" | ||
37 | |||
38 | /* #define DOWN_VARIABLE_DPLL 1 */ /* Experimental */ | ||
39 | |||
40 | /** | ||
41 | * omap2xxx_clk_get_core_rate - return the CORE_CLK rate | ||
42 | * @clk: pointer to the combined dpll_ck + core_ck (currently "dpll_ck") | ||
43 | * | ||
44 | * Returns the CORE_CLK rate. CORE_CLK can have one of three rate | ||
45 | * sources on OMAP2xxx: the DPLL CLKOUT rate, DPLL CLKOUTX2, or 32KHz | ||
46 | * (the latter is unusual). This currently should be called with | ||
47 | * struct clk *dpll_ck, which is a composite clock of dpll_ck and | ||
48 | * core_ck. | ||
49 | */ | ||
50 | unsigned long omap2xxx_clk_get_core_rate(struct clk *clk) | ||
51 | { | ||
52 | long long core_clk; | ||
53 | u32 v; | ||
54 | |||
55 | core_clk = omap2_get_dpll_rate(clk); | ||
56 | |||
57 | v = cm_read_mod_reg(PLL_MOD, CM_CLKSEL2); | ||
58 | v &= OMAP24XX_CORE_CLK_SRC_MASK; | ||
59 | |||
60 | if (v == CORE_CLK_SRC_32K) | ||
61 | core_clk = 32768; | ||
62 | else | ||
63 | core_clk *= v; | ||
64 | |||
65 | return core_clk; | ||
66 | } | ||
67 | |||
68 | /* | ||
69 | * Uses the current prcm set to tell if a rate is valid. | ||
70 | * You can go slower, but not faster within a given rate set. | ||
71 | */ | ||
72 | static long omap2_dpllcore_round_rate(unsigned long target_rate) | ||
73 | { | ||
74 | u32 high, low, core_clk_src; | ||
75 | |||
76 | core_clk_src = cm_read_mod_reg(PLL_MOD, CM_CLKSEL2); | ||
77 | core_clk_src &= OMAP24XX_CORE_CLK_SRC_MASK; | ||
78 | |||
79 | if (core_clk_src == CORE_CLK_SRC_DPLL) { /* DPLL clockout */ | ||
80 | high = curr_prcm_set->dpll_speed * 2; | ||
81 | low = curr_prcm_set->dpll_speed; | ||
82 | } else { /* DPLL clockout x 2 */ | ||
83 | high = curr_prcm_set->dpll_speed; | ||
84 | low = curr_prcm_set->dpll_speed / 2; | ||
85 | } | ||
86 | |||
87 | #ifdef DOWN_VARIABLE_DPLL | ||
88 | if (target_rate > high) | ||
89 | return high; | ||
90 | else | ||
91 | return target_rate; | ||
92 | #else | ||
93 | if (target_rate > low) | ||
94 | return high; | ||
95 | else | ||
96 | return low; | ||
97 | #endif | ||
98 | |||
99 | } | ||
100 | |||
101 | unsigned long omap2_dpllcore_recalc(struct clk *clk) | ||
102 | { | ||
103 | return omap2xxx_clk_get_core_rate(clk); | ||
104 | } | ||
105 | |||
106 | int omap2_reprogram_dpllcore(struct clk *clk, unsigned long rate) | ||
107 | { | ||
108 | u32 cur_rate, low, mult, div, valid_rate, done_rate; | ||
109 | u32 bypass = 0; | ||
110 | struct prcm_config tmpset; | ||
111 | const struct dpll_data *dd; | ||
112 | |||
113 | cur_rate = omap2xxx_clk_get_core_rate(dclk); | ||
114 | mult = cm_read_mod_reg(PLL_MOD, CM_CLKSEL2); | ||
115 | mult &= OMAP24XX_CORE_CLK_SRC_MASK; | ||
116 | |||
117 | if ((rate == (cur_rate / 2)) && (mult == 2)) { | ||
118 | omap2xxx_sdrc_reprogram(CORE_CLK_SRC_DPLL, 1); | ||
119 | } else if ((rate == (cur_rate * 2)) && (mult == 1)) { | ||
120 | omap2xxx_sdrc_reprogram(CORE_CLK_SRC_DPLL_X2, 1); | ||
121 | } else if (rate != cur_rate) { | ||
122 | valid_rate = omap2_dpllcore_round_rate(rate); | ||
123 | if (valid_rate != rate) | ||
124 | return -EINVAL; | ||
125 | |||
126 | if (mult == 1) | ||
127 | low = curr_prcm_set->dpll_speed; | ||
128 | else | ||
129 | low = curr_prcm_set->dpll_speed / 2; | ||
130 | |||
131 | dd = clk->dpll_data; | ||
132 | if (!dd) | ||
133 | return -EINVAL; | ||
134 | |||
135 | tmpset.cm_clksel1_pll = __raw_readl(dd->mult_div1_reg); | ||
136 | tmpset.cm_clksel1_pll &= ~(dd->mult_mask | | ||
137 | dd->div1_mask); | ||
138 | div = ((curr_prcm_set->xtal_speed / 1000000) - 1); | ||
139 | tmpset.cm_clksel2_pll = cm_read_mod_reg(PLL_MOD, CM_CLKSEL2); | ||
140 | tmpset.cm_clksel2_pll &= ~OMAP24XX_CORE_CLK_SRC_MASK; | ||
141 | if (rate > low) { | ||
142 | tmpset.cm_clksel2_pll |= CORE_CLK_SRC_DPLL_X2; | ||
143 | mult = ((rate / 2) / 1000000); | ||
144 | done_rate = CORE_CLK_SRC_DPLL_X2; | ||
145 | } else { | ||
146 | tmpset.cm_clksel2_pll |= CORE_CLK_SRC_DPLL; | ||
147 | mult = (rate / 1000000); | ||
148 | done_rate = CORE_CLK_SRC_DPLL; | ||
149 | } | ||
150 | tmpset.cm_clksel1_pll |= (div << __ffs(dd->mult_mask)); | ||
151 | tmpset.cm_clksel1_pll |= (mult << __ffs(dd->div1_mask)); | ||
152 | |||
153 | /* Worst case */ | ||
154 | tmpset.base_sdrc_rfr = SDRC_RFR_CTRL_BYPASS; | ||
155 | |||
156 | if (rate == curr_prcm_set->xtal_speed) /* If asking for 1-1 */ | ||
157 | bypass = 1; | ||
158 | |||
159 | /* For omap2xxx_sdrc_init_params() */ | ||
160 | omap2xxx_sdrc_reprogram(CORE_CLK_SRC_DPLL_X2, 1); | ||
161 | |||
162 | /* Force dll lock mode */ | ||
163 | omap2_set_prcm(tmpset.cm_clksel1_pll, tmpset.base_sdrc_rfr, | ||
164 | bypass); | ||
165 | |||
166 | /* Errata: ret dll entry state */ | ||
167 | omap2xxx_sdrc_init_params(omap2xxx_sdrc_dll_is_unlocked()); | ||
168 | omap2xxx_sdrc_reprogram(done_rate, 0); | ||
169 | } | ||
170 | |||
171 | return 0; | ||
172 | } | ||
173 | |||
diff --git a/arch/arm/mach-omap2/clock2xxx.c b/arch/arm/mach-omap2/clock2xxx.c index bef557488fec..419ae80fa1d4 100644 --- a/arch/arm/mach-omap2/clock2xxx.c +++ b/arch/arm/mach-omap2/clock2xxx.c | |||
@@ -54,8 +54,6 @@ | |||
54 | #define APLLS_CLKIN_13MHZ 2 | 54 | #define APLLS_CLKIN_13MHZ 2 |
55 | #define APLLS_CLKIN_12MHZ 3 | 55 | #define APLLS_CLKIN_12MHZ 3 |
56 | 56 | ||
57 | /* #define DOWN_VARIABLE_DPLL 1 */ /* Experimental */ | ||
58 | |||
59 | const struct prcm_config *curr_prcm_set; | 57 | const struct prcm_config *curr_prcm_set; |
60 | const struct prcm_config *rate_table; | 58 | const struct prcm_config *rate_table; |
61 | 59 | ||
@@ -94,34 +92,6 @@ const struct clkops clkops_omap2430_i2chs_wait = { | |||
94 | .find_companion = omap2_clk_dflt_find_companion, | 92 | .find_companion = omap2_clk_dflt_find_companion, |
95 | }; | 93 | }; |
96 | 94 | ||
97 | /** | ||
98 | * omap2xxx_clk_get_core_rate - return the CORE_CLK rate | ||
99 | * @clk: pointer to the combined dpll_ck + core_ck (currently "dpll_ck") | ||
100 | * | ||
101 | * Returns the CORE_CLK rate. CORE_CLK can have one of three rate | ||
102 | * sources on OMAP2xxx: the DPLL CLKOUT rate, DPLL CLKOUTX2, or 32KHz | ||
103 | * (the latter is unusual). This currently should be called with | ||
104 | * struct clk *dpll_ck, which is a composite clock of dpll_ck and | ||
105 | * core_ck. | ||
106 | */ | ||
107 | unsigned long omap2xxx_clk_get_core_rate(struct clk *clk) | ||
108 | { | ||
109 | long long core_clk; | ||
110 | u32 v; | ||
111 | |||
112 | core_clk = omap2_get_dpll_rate(clk); | ||
113 | |||
114 | v = cm_read_mod_reg(PLL_MOD, CM_CLKSEL2); | ||
115 | v &= OMAP24XX_CORE_CLK_SRC_MASK; | ||
116 | |||
117 | if (v == CORE_CLK_SRC_32K) | ||
118 | core_clk = 32768; | ||
119 | else | ||
120 | core_clk *= v; | ||
121 | |||
122 | return core_clk; | ||
123 | } | ||
124 | |||
125 | static int omap2_enable_osc_ck(struct clk *clk) | 95 | static int omap2_enable_osc_ck(struct clk *clk) |
126 | { | 96 | { |
127 | u32 pcc; | 97 | u32 pcc; |
@@ -215,112 +185,6 @@ const struct clkops clkops_apll54 = { | |||
215 | .disable = omap2_clk_apll_disable, | 185 | .disable = omap2_clk_apll_disable, |
216 | }; | 186 | }; |
217 | 187 | ||
218 | /* | ||
219 | * Uses the current prcm set to tell if a rate is valid. | ||
220 | * You can go slower, but not faster within a given rate set. | ||
221 | */ | ||
222 | long omap2_dpllcore_round_rate(unsigned long target_rate) | ||
223 | { | ||
224 | u32 high, low, core_clk_src; | ||
225 | |||
226 | core_clk_src = cm_read_mod_reg(PLL_MOD, CM_CLKSEL2); | ||
227 | core_clk_src &= OMAP24XX_CORE_CLK_SRC_MASK; | ||
228 | |||
229 | if (core_clk_src == CORE_CLK_SRC_DPLL) { /* DPLL clockout */ | ||
230 | high = curr_prcm_set->dpll_speed * 2; | ||
231 | low = curr_prcm_set->dpll_speed; | ||
232 | } else { /* DPLL clockout x 2 */ | ||
233 | high = curr_prcm_set->dpll_speed; | ||
234 | low = curr_prcm_set->dpll_speed / 2; | ||
235 | } | ||
236 | |||
237 | #ifdef DOWN_VARIABLE_DPLL | ||
238 | if (target_rate > high) | ||
239 | return high; | ||
240 | else | ||
241 | return target_rate; | ||
242 | #else | ||
243 | if (target_rate > low) | ||
244 | return high; | ||
245 | else | ||
246 | return low; | ||
247 | #endif | ||
248 | |||
249 | } | ||
250 | |||
251 | unsigned long omap2_dpllcore_recalc(struct clk *clk) | ||
252 | { | ||
253 | return omap2xxx_clk_get_core_rate(clk); | ||
254 | } | ||
255 | |||
256 | int omap2_reprogram_dpllcore(struct clk *clk, unsigned long rate) | ||
257 | { | ||
258 | u32 cur_rate, low, mult, div, valid_rate, done_rate; | ||
259 | u32 bypass = 0; | ||
260 | struct prcm_config tmpset; | ||
261 | const struct dpll_data *dd; | ||
262 | |||
263 | cur_rate = omap2xxx_clk_get_core_rate(dclk); | ||
264 | mult = cm_read_mod_reg(PLL_MOD, CM_CLKSEL2); | ||
265 | mult &= OMAP24XX_CORE_CLK_SRC_MASK; | ||
266 | |||
267 | if ((rate == (cur_rate / 2)) && (mult == 2)) { | ||
268 | omap2xxx_sdrc_reprogram(CORE_CLK_SRC_DPLL, 1); | ||
269 | } else if ((rate == (cur_rate * 2)) && (mult == 1)) { | ||
270 | omap2xxx_sdrc_reprogram(CORE_CLK_SRC_DPLL_X2, 1); | ||
271 | } else if (rate != cur_rate) { | ||
272 | valid_rate = omap2_dpllcore_round_rate(rate); | ||
273 | if (valid_rate != rate) | ||
274 | return -EINVAL; | ||
275 | |||
276 | if (mult == 1) | ||
277 | low = curr_prcm_set->dpll_speed; | ||
278 | else | ||
279 | low = curr_prcm_set->dpll_speed / 2; | ||
280 | |||
281 | dd = clk->dpll_data; | ||
282 | if (!dd) | ||
283 | return -EINVAL; | ||
284 | |||
285 | tmpset.cm_clksel1_pll = __raw_readl(dd->mult_div1_reg); | ||
286 | tmpset.cm_clksel1_pll &= ~(dd->mult_mask | | ||
287 | dd->div1_mask); | ||
288 | div = ((curr_prcm_set->xtal_speed / 1000000) - 1); | ||
289 | tmpset.cm_clksel2_pll = cm_read_mod_reg(PLL_MOD, CM_CLKSEL2); | ||
290 | tmpset.cm_clksel2_pll &= ~OMAP24XX_CORE_CLK_SRC_MASK; | ||
291 | if (rate > low) { | ||
292 | tmpset.cm_clksel2_pll |= CORE_CLK_SRC_DPLL_X2; | ||
293 | mult = ((rate / 2) / 1000000); | ||
294 | done_rate = CORE_CLK_SRC_DPLL_X2; | ||
295 | } else { | ||
296 | tmpset.cm_clksel2_pll |= CORE_CLK_SRC_DPLL; | ||
297 | mult = (rate / 1000000); | ||
298 | done_rate = CORE_CLK_SRC_DPLL; | ||
299 | } | ||
300 | tmpset.cm_clksel1_pll |= (div << __ffs(dd->mult_mask)); | ||
301 | tmpset.cm_clksel1_pll |= (mult << __ffs(dd->div1_mask)); | ||
302 | |||
303 | /* Worst case */ | ||
304 | tmpset.base_sdrc_rfr = SDRC_RFR_CTRL_BYPASS; | ||
305 | |||
306 | if (rate == curr_prcm_set->xtal_speed) /* If asking for 1-1 */ | ||
307 | bypass = 1; | ||
308 | |||
309 | /* For omap2xxx_sdrc_init_params() */ | ||
310 | omap2xxx_sdrc_reprogram(CORE_CLK_SRC_DPLL_X2, 1); | ||
311 | |||
312 | /* Force dll lock mode */ | ||
313 | omap2_set_prcm(tmpset.cm_clksel1_pll, tmpset.base_sdrc_rfr, | ||
314 | bypass); | ||
315 | |||
316 | /* Errata: ret dll entry state */ | ||
317 | omap2xxx_sdrc_init_params(omap2xxx_sdrc_dll_is_unlocked()); | ||
318 | omap2xxx_sdrc_reprogram(done_rate, 0); | ||
319 | } | ||
320 | |||
321 | return 0; | ||
322 | } | ||
323 | |||
324 | /** | 188 | /** |
325 | * omap2_table_mpu_recalc - just return the MPU speed | 189 | * omap2_table_mpu_recalc - just return the MPU speed |
326 | * @clk: virt_prcm_set struct clk | 190 | * @clk: virt_prcm_set struct clk |