diff options
author | Steven Miao <realmz6@gmail.com> | 2012-05-16 05:49:52 -0400 |
---|---|---|
committer | Bob Liu <lliubbo@gmail.com> | 2012-05-21 02:54:13 -0400 |
commit | 969003152aa9085e50ce23822c60fab82222ecef (patch) | |
tree | ab12a8c8bf20706d624ef7ad6b540cc8776d954f | |
parent | b5affb0147cee0ea05d909396f8e389092729236 (diff) |
blackfin: bf60x: add clock support
Add clock support for bf60x.
Signed-off-by: Steven Miao <realmz6@gmail.com>
Signed-off-by: Bob Liu <lliubbo@gmail.com>
-rw-r--r-- | arch/blackfin/include/asm/clkdev.h | 14 | ||||
-rw-r--r-- | arch/blackfin/include/asm/clocks.h | 23 | ||||
-rw-r--r-- | arch/blackfin/mach-bf609/clock.c | 390 | ||||
-rw-r--r-- | arch/blackfin/mach-common/clock.h | 27 | ||||
-rw-r--r-- | arch/blackfin/mach-common/clocks-init.c | 4 | ||||
-rw-r--r-- | arch/blackfin/mach-common/cpufreq.c | 39 |
6 files changed, 495 insertions, 2 deletions
diff --git a/arch/blackfin/include/asm/clkdev.h b/arch/blackfin/include/asm/clkdev.h new file mode 100644 index 000000000000..9053beda8c50 --- /dev/null +++ b/arch/blackfin/include/asm/clkdev.h | |||
@@ -0,0 +1,14 @@ | |||
1 | #ifndef __ASM_CLKDEV__H_ | ||
2 | #define __ASM_CLKDEV__H_ | ||
3 | |||
4 | #include <linux/slab.h> | ||
5 | |||
6 | static inline struct clk_lookup_alloc *__clkdev_alloc(size_t size) | ||
7 | { | ||
8 | return kzalloc(size, GFP_KERNEL); | ||
9 | } | ||
10 | |||
11 | #define __clk_put(clk) | ||
12 | #define __clk_get(clk) ({ 1; }) | ||
13 | |||
14 | #endif | ||
diff --git a/arch/blackfin/include/asm/clocks.h b/arch/blackfin/include/asm/clocks.h index 6f0b61852f58..9b3c85b3c288 100644 --- a/arch/blackfin/include/asm/clocks.h +++ b/arch/blackfin/include/asm/clocks.h | |||
@@ -48,4 +48,27 @@ | |||
48 | # define CONFIG_VCO_MULT 0 | 48 | # define CONFIG_VCO_MULT 0 |
49 | #endif | 49 | #endif |
50 | 50 | ||
51 | #include <linux/clk.h> | ||
52 | |||
53 | struct clk_ops { | ||
54 | unsigned long (*get_rate)(struct clk *clk); | ||
55 | unsigned long (*round_rate)(struct clk *clk, unsigned long rate); | ||
56 | int (*set_rate)(struct clk *clk, unsigned long rate); | ||
57 | int (*enable)(struct clk *clk); | ||
58 | int (*disable)(struct clk *clk); | ||
59 | }; | ||
60 | |||
61 | struct clk { | ||
62 | struct clk *parent; | ||
63 | const char *name; | ||
64 | unsigned long rate; | ||
65 | spinlock_t lock; | ||
66 | u32 flags; | ||
67 | const struct clk_ops *ops; | ||
68 | void __iomem *reg; | ||
69 | u32 mask; | ||
70 | u32 shift; | ||
71 | }; | ||
72 | |||
73 | int clk_init(void); | ||
51 | #endif | 74 | #endif |
diff --git a/arch/blackfin/mach-bf609/clock.c b/arch/blackfin/mach-bf609/clock.c new file mode 100644 index 000000000000..b50412c8cab0 --- /dev/null +++ b/arch/blackfin/mach-bf609/clock.c | |||
@@ -0,0 +1,390 @@ | |||
1 | #include <linux/module.h> | ||
2 | #include <linux/kernel.h> | ||
3 | #include <linux/list.h> | ||
4 | #include <linux/errno.h> | ||
5 | #include <linux/err.h> | ||
6 | #include <linux/string.h> | ||
7 | #include <linux/clk.h> | ||
8 | #include <linux/mutex.h> | ||
9 | #include <linux/spinlock.h> | ||
10 | #include <linux/debugfs.h> | ||
11 | #include <linux/device.h> | ||
12 | #include <linux/init.h> | ||
13 | #include <linux/timer.h> | ||
14 | #include <linux/io.h> | ||
15 | #include <linux/seq_file.h> | ||
16 | #include <linux/clkdev.h> | ||
17 | |||
18 | #include <asm/clocks.h> | ||
19 | |||
20 | #define CGU0_CTL_DF (1 << 0) | ||
21 | |||
22 | #define CGU0_CTL_MSEL_SHIFT 8 | ||
23 | #define CGU0_CTL_MSEL_MASK (0x7f << 8) | ||
24 | |||
25 | #define CGU0_STAT_PLLEN (1 << 0) | ||
26 | #define CGU0_STAT_PLLBP (1 << 1) | ||
27 | #define CGU0_STAT_PLLLK (1 << 2) | ||
28 | #define CGU0_STAT_CLKSALGN (1 << 3) | ||
29 | #define CGU0_STAT_CCBF0 (1 << 4) | ||
30 | #define CGU0_STAT_CCBF1 (1 << 5) | ||
31 | #define CGU0_STAT_SCBF0 (1 << 6) | ||
32 | #define CGU0_STAT_SCBF1 (1 << 7) | ||
33 | #define CGU0_STAT_DCBF (1 << 8) | ||
34 | #define CGU0_STAT_OCBF (1 << 9) | ||
35 | #define CGU0_STAT_ADDRERR (1 << 16) | ||
36 | #define CGU0_STAT_LWERR (1 << 17) | ||
37 | #define CGU0_STAT_DIVERR (1 << 18) | ||
38 | #define CGU0_STAT_WDFMSERR (1 << 19) | ||
39 | #define CGU0_STAT_WDIVERR (1 << 20) | ||
40 | #define CGU0_STAT_PLOCKERR (1 << 21) | ||
41 | |||
42 | #define CGU0_DIV_CSEL_SHIFT 0 | ||
43 | #define CGU0_DIV_CSEL_MASK 0x0000001F | ||
44 | #define CGU0_DIV_S0SEL_SHIFT 5 | ||
45 | #define CGU0_DIV_S0SEL_MASK (0x3 << CGU0_DIV_S0SEL_SHIFT) | ||
46 | #define CGU0_DIV_SYSSEL_SHIFT 8 | ||
47 | #define CGU0_DIV_SYSSEL_MASK (0x1f << CGU0_DIV_SYSSEL_SHIFT) | ||
48 | #define CGU0_DIV_S1SEL_SHIFT 13 | ||
49 | #define CGU0_DIV_S1SEL_MASK (0x3 << CGU0_DIV_S1SEL_SHIFT) | ||
50 | #define CGU0_DIV_DSEL_SHIFT 16 | ||
51 | #define CGU0_DIV_DSEL_MASK (0x1f << CGU0_DIV_DSEL_SHIFT) | ||
52 | #define CGU0_DIV_OSEL_SHIFT 22 | ||
53 | #define CGU0_DIV_OSEL_MASK (0x7f << CGU0_DIV_OSEL_SHIFT) | ||
54 | |||
55 | #define CLK(_clk, _devname, _conname) \ | ||
56 | { \ | ||
57 | .clk = &_clk, \ | ||
58 | .dev_id = _devname, \ | ||
59 | .con_id = _conname, \ | ||
60 | } | ||
61 | |||
62 | #define NEEDS_INITIALIZATION 0x11 | ||
63 | |||
64 | static LIST_HEAD(clk_list); | ||
65 | |||
66 | static void clk_reg_write_mask(u32 reg, uint32_t val, uint32_t mask) | ||
67 | { | ||
68 | u32 val2; | ||
69 | |||
70 | val2 = bfin_read32(reg); | ||
71 | val2 &= ~mask; | ||
72 | val2 |= val; | ||
73 | bfin_write32(reg, val2); | ||
74 | } | ||
75 | |||
76 | static void clk_reg_set_bits(u32 reg, uint32_t mask) | ||
77 | { | ||
78 | u32 val; | ||
79 | |||
80 | val = bfin_read32(reg); | ||
81 | val |= mask; | ||
82 | bfin_write32(reg, val); | ||
83 | } | ||
84 | |||
85 | static void clk_reg_clear_bits(u32 reg, uint32_t mask) | ||
86 | { | ||
87 | u32 val; | ||
88 | |||
89 | val = bfin_read32(reg); | ||
90 | val &= ~mask; | ||
91 | bfin_write32(reg, val); | ||
92 | } | ||
93 | |||
94 | int wait_for_pll_align(void) | ||
95 | { | ||
96 | int i = 10000; | ||
97 | while (i-- && (bfin_read32(CGU0_STAT) & CGU0_STAT_CLKSALGN)); | ||
98 | |||
99 | if (bfin_read32(CGU0_STAT) & CGU0_STAT_CLKSALGN) { | ||
100 | printk(KERN_DEBUG "fail to align clk\n"); | ||
101 | return -1; | ||
102 | } | ||
103 | return 0; | ||
104 | } | ||
105 | |||
106 | int clk_enable(struct clk *clk) | ||
107 | { | ||
108 | int ret = -EIO; | ||
109 | if (clk->ops && clk->ops->enable) | ||
110 | ret = clk->ops->enable(clk); | ||
111 | return ret; | ||
112 | } | ||
113 | EXPORT_SYMBOL(clk_enable); | ||
114 | |||
115 | void clk_disable(struct clk *clk) | ||
116 | { | ||
117 | if (clk->ops && clk->ops->disable) | ||
118 | clk->ops->disable(clk); | ||
119 | } | ||
120 | EXPORT_SYMBOL(clk_disable); | ||
121 | |||
122 | unsigned long clk_get_rate(struct clk *clk) | ||
123 | { | ||
124 | unsigned long ret = 0; | ||
125 | if (clk->ops && clk->ops->get_rate) | ||
126 | ret = clk->ops->get_rate(clk); | ||
127 | return ret; | ||
128 | } | ||
129 | EXPORT_SYMBOL(clk_get_rate); | ||
130 | |||
131 | long clk_round_rate(struct clk *clk, unsigned long rate) | ||
132 | { | ||
133 | long ret = -EIO; | ||
134 | if (clk->ops && clk->ops->round_rate) | ||
135 | ret = clk->ops->round_rate(clk, rate); | ||
136 | return ret; | ||
137 | } | ||
138 | EXPORT_SYMBOL(clk_round_rate); | ||
139 | |||
140 | int clk_set_rate(struct clk *clk, unsigned long rate) | ||
141 | { | ||
142 | int ret = -EIO; | ||
143 | if (clk->ops && clk->ops->set_rate) | ||
144 | ret = clk->ops->set_rate(clk, rate); | ||
145 | return ret; | ||
146 | } | ||
147 | EXPORT_SYMBOL(clk_set_rate); | ||
148 | |||
149 | unsigned long vco_get_rate(struct clk *clk) | ||
150 | { | ||
151 | return clk->rate; | ||
152 | } | ||
153 | |||
154 | unsigned long pll_get_rate(struct clk *clk) | ||
155 | { | ||
156 | u32 df; | ||
157 | u32 msel; | ||
158 | u32 ctl = bfin_read32(CGU0_CTL); | ||
159 | u32 stat = bfin_read32(CGU0_STAT); | ||
160 | if (stat & CGU0_STAT_PLLBP) | ||
161 | return 0; | ||
162 | msel = (ctl & CGU0_CTL_MSEL_MASK) >> CGU0_CTL_MSEL_SHIFT; | ||
163 | df = (ctl & CGU0_CTL_DF); | ||
164 | clk->parent->rate = clk_get_rate(clk->parent); | ||
165 | return clk->parent->rate / (df + 1) * msel * 2; | ||
166 | } | ||
167 | |||
168 | unsigned long pll_round_rate(struct clk *clk, unsigned long rate) | ||
169 | { | ||
170 | u32 div; | ||
171 | div = rate / clk->parent->rate; | ||
172 | return clk->parent->rate * div; | ||
173 | } | ||
174 | |||
175 | int pll_set_rate(struct clk *clk, unsigned long rate) | ||
176 | { | ||
177 | u32 msel; | ||
178 | u32 stat = bfin_read32(CGU0_STAT); | ||
179 | if (!(stat & CGU0_STAT_PLLEN)) | ||
180 | return -EBUSY; | ||
181 | if (!(stat & CGU0_STAT_PLLLK)) | ||
182 | return -EBUSY; | ||
183 | if (wait_for_pll_align()) | ||
184 | return -EBUSY; | ||
185 | msel = rate / clk->parent->rate / 2; | ||
186 | clk_reg_write_mask(CGU0_CTL, msel << CGU0_CTL_MSEL_SHIFT, | ||
187 | CGU0_CTL_MSEL_MASK); | ||
188 | clk->rate = rate; | ||
189 | return 0; | ||
190 | } | ||
191 | |||
192 | unsigned long cclk_get_rate(struct clk *clk) | ||
193 | { | ||
194 | if (clk->parent) | ||
195 | return clk->parent->rate; | ||
196 | else | ||
197 | return 0; | ||
198 | } | ||
199 | |||
200 | unsigned long sys_clk_get_rate(struct clk *clk) | ||
201 | { | ||
202 | unsigned long drate; | ||
203 | u32 msel; | ||
204 | u32 df; | ||
205 | u32 ctl = bfin_read32(CGU0_CTL); | ||
206 | u32 div = bfin_read32(CGU0_DIV); | ||
207 | div = (div & clk->mask) >> clk->shift; | ||
208 | msel = (ctl & CGU0_CTL_MSEL_MASK) >> CGU0_CTL_MSEL_SHIFT; | ||
209 | df = (ctl & CGU0_CTL_DF); | ||
210 | |||
211 | if (!strcmp(clk->parent->name, "SYS_CLKIN")) { | ||
212 | drate = clk->parent->rate / (df + 1); | ||
213 | drate *= msel; | ||
214 | drate /= div; | ||
215 | return drate; | ||
216 | } else { | ||
217 | clk->parent->rate = clk_get_rate(clk->parent); | ||
218 | return clk->parent->rate / div; | ||
219 | } | ||
220 | } | ||
221 | |||
222 | unsigned long sys_clk_round_rate(struct clk *clk, unsigned long rate) | ||
223 | { | ||
224 | unsigned long max_rate; | ||
225 | unsigned long drate; | ||
226 | int i; | ||
227 | u32 msel; | ||
228 | u32 df; | ||
229 | u32 ctl = bfin_read32(CGU0_CTL); | ||
230 | |||
231 | msel = (ctl & CGU0_CTL_MSEL_MASK) >> CGU0_CTL_MSEL_SHIFT; | ||
232 | df = (ctl & CGU0_CTL_DF); | ||
233 | max_rate = clk->parent->rate / (df + 1) * msel; | ||
234 | |||
235 | if (rate > max_rate) | ||
236 | return 0; | ||
237 | |||
238 | for (i = 1; i < clk->mask; i++) { | ||
239 | drate = max_rate / i; | ||
240 | if (rate >= drate) | ||
241 | return drate; | ||
242 | } | ||
243 | return 0; | ||
244 | } | ||
245 | |||
246 | int sys_clk_set_rate(struct clk *clk, unsigned long rate) | ||
247 | { | ||
248 | u32 div = bfin_read32(CGU0_DIV); | ||
249 | div = (div & clk->mask) >> clk->shift; | ||
250 | |||
251 | rate = clk_round_rate(clk, rate); | ||
252 | |||
253 | if (!rate) | ||
254 | return -EINVAL; | ||
255 | |||
256 | div = (clk_get_rate(clk) * div) / rate; | ||
257 | |||
258 | if (wait_for_pll_align()) | ||
259 | return -EBUSY; | ||
260 | clk_reg_write_mask(CGU0_DIV, div << clk->shift, | ||
261 | clk->mask); | ||
262 | clk->rate = rate; | ||
263 | return 0; | ||
264 | } | ||
265 | |||
266 | static struct clk_ops vco_ops = { | ||
267 | .get_rate = vco_get_rate, | ||
268 | }; | ||
269 | |||
270 | static struct clk_ops pll_ops = { | ||
271 | .get_rate = pll_get_rate, | ||
272 | .set_rate = pll_set_rate, | ||
273 | }; | ||
274 | |||
275 | static struct clk_ops cclk_ops = { | ||
276 | .get_rate = cclk_get_rate, | ||
277 | }; | ||
278 | |||
279 | static struct clk_ops sys_clk_ops = { | ||
280 | .get_rate = sys_clk_get_rate, | ||
281 | .set_rate = sys_clk_set_rate, | ||
282 | .round_rate = sys_clk_round_rate, | ||
283 | }; | ||
284 | |||
285 | static struct clk sys_clkin = { | ||
286 | .name = "SYS_CLKIN", | ||
287 | .rate = CONFIG_CLKIN_HZ, | ||
288 | .ops = &vco_ops, | ||
289 | }; | ||
290 | |||
291 | static struct clk pll_clk = { | ||
292 | .name = "PLLCLK", | ||
293 | .rate = 500000000, | ||
294 | .parent = &sys_clkin, | ||
295 | .ops = &pll_ops, | ||
296 | .flags = NEEDS_INITIALIZATION, | ||
297 | }; | ||
298 | |||
299 | static struct clk cclk = { | ||
300 | .name = "CCLK", | ||
301 | .rate = 500000000, | ||
302 | .mask = CGU0_DIV_CSEL_MASK, | ||
303 | .shift = CGU0_DIV_CSEL_SHIFT, | ||
304 | .parent = &sys_clkin, | ||
305 | .ops = &sys_clk_ops, | ||
306 | .flags = NEEDS_INITIALIZATION, | ||
307 | }; | ||
308 | |||
309 | static struct clk cclk0 = { | ||
310 | .name = "CCLK0", | ||
311 | .parent = &cclk, | ||
312 | .ops = &cclk_ops, | ||
313 | }; | ||
314 | |||
315 | static struct clk cclk1 = { | ||
316 | .name = "CCLK1", | ||
317 | .parent = &cclk, | ||
318 | .ops = &cclk_ops, | ||
319 | }; | ||
320 | |||
321 | static struct clk sysclk = { | ||
322 | .name = "SYSCLK", | ||
323 | .rate = 500000000, | ||
324 | .mask = CGU0_DIV_SYSSEL_MASK, | ||
325 | .shift = CGU0_DIV_SYSSEL_SHIFT, | ||
326 | .parent = &sys_clkin, | ||
327 | .ops = &sys_clk_ops, | ||
328 | .flags = NEEDS_INITIALIZATION, | ||
329 | }; | ||
330 | |||
331 | static struct clk sclk0 = { | ||
332 | .name = "SCLK0", | ||
333 | .rate = 500000000, | ||
334 | .mask = CGU0_DIV_S0SEL_MASK, | ||
335 | .shift = CGU0_DIV_S0SEL_SHIFT, | ||
336 | .parent = &sysclk, | ||
337 | .ops = &sys_clk_ops, | ||
338 | }; | ||
339 | |||
340 | static struct clk sclk1 = { | ||
341 | .name = "SCLK1", | ||
342 | .rate = 500000000, | ||
343 | .mask = CGU0_DIV_S1SEL_MASK, | ||
344 | .shift = CGU0_DIV_S1SEL_SHIFT, | ||
345 | .parent = &sysclk, | ||
346 | .ops = &sys_clk_ops, | ||
347 | }; | ||
348 | |||
349 | static struct clk dclk = { | ||
350 | .name = "DCLK", | ||
351 | .rate = 500000000, | ||
352 | .mask = CGU0_DIV_DSEL_MASK, | ||
353 | .shift = CGU0_DIV_DSEL_SHIFT, | ||
354 | .parent = &pll_clk, | ||
355 | .ops = &sys_clk_ops, | ||
356 | }; | ||
357 | |||
358 | static struct clk oclk = { | ||
359 | .name = "OCLK", | ||
360 | .rate = 500000000, | ||
361 | .mask = CGU0_DIV_OSEL_MASK, | ||
362 | .shift = CGU0_DIV_OSEL_SHIFT, | ||
363 | .parent = &pll_clk, | ||
364 | }; | ||
365 | |||
366 | static struct clk_lookup bf609_clks[] = { | ||
367 | CLK(sys_clkin, NULL, "SYS_CLKIN"), | ||
368 | CLK(pll_clk, NULL, "PLLCLK"), | ||
369 | CLK(cclk, NULL, "CCLK"), | ||
370 | CLK(cclk0, NULL, "CCLK0"), | ||
371 | CLK(cclk1, NULL, "CCLK1"), | ||
372 | CLK(sysclk, NULL, "SYSCLK"), | ||
373 | CLK(sclk0, NULL, "SCLK0"), | ||
374 | CLK(sclk1, NULL, "SCLK1"), | ||
375 | CLK(dclk, NULL, "DCLK"), | ||
376 | CLK(oclk, NULL, "OCLK"), | ||
377 | }; | ||
378 | |||
379 | int __init clk_init(void) | ||
380 | { | ||
381 | int i; | ||
382 | struct clk *clkp; | ||
383 | for (i = 0; i < ARRAY_SIZE(bf609_clks); i++) { | ||
384 | clkp = bf609_clks[i].clk; | ||
385 | if (clkp->flags & NEEDS_INITIALIZATION) | ||
386 | clk_get_rate(clkp); | ||
387 | } | ||
388 | clkdev_add_table(bf609_clks, ARRAY_SIZE(bf609_clks)); | ||
389 | return 0; | ||
390 | } | ||
diff --git a/arch/blackfin/mach-common/clock.h b/arch/blackfin/mach-common/clock.h new file mode 100644 index 000000000000..645ff460a1f2 --- /dev/null +++ b/arch/blackfin/mach-common/clock.h | |||
@@ -0,0 +1,27 @@ | |||
1 | #ifndef __MACH_COMMON_CLKDEV_H | ||
2 | #define __MACH_COMMON_CLKDEV_H | ||
3 | |||
4 | #include <linux/clk.h> | ||
5 | |||
6 | struct clk_ops { | ||
7 | unsigned long (*get_rate)(struct clk *clk); | ||
8 | unsigned long (*round_rate)(struct clk *clk, unsigned long rate); | ||
9 | int (*set_rate)(struct clk *clk, unsigned long rate); | ||
10 | int (*enable)(struct clk *clk); | ||
11 | int (*disable)(struct clk *clk); | ||
12 | }; | ||
13 | |||
14 | struct clk { | ||
15 | const char *name; | ||
16 | unsigned long rate; | ||
17 | spinlock_t lock; | ||
18 | u32 flags; | ||
19 | const struct clk_ops *ops; | ||
20 | const struct params *params; | ||
21 | void __iomem *reg; | ||
22 | u32 mask; | ||
23 | u32 shift; | ||
24 | }; | ||
25 | |||
26 | #endif | ||
27 | |||
diff --git a/arch/blackfin/mach-common/clocks-init.c b/arch/blackfin/mach-common/clocks-init.c index d5cfe611b778..1e6beca8d403 100644 --- a/arch/blackfin/mach-common/clocks-init.c +++ b/arch/blackfin/mach-common/clocks-init.c | |||
@@ -33,6 +33,8 @@ void init_clocks(void) | |||
33 | * in the middle of reprogramming things, and that'll screw us up. | 33 | * in the middle of reprogramming things, and that'll screw us up. |
34 | * For example, any automatic DMAs left by U-Boot for splash screens. | 34 | * For example, any automatic DMAs left by U-Boot for splash screens. |
35 | */ | 35 | */ |
36 | |||
37 | #if 0 | ||
36 | size_t i; | 38 | size_t i; |
37 | for (i = 0; i < MAX_DMA_CHANNELS; ++i) { | 39 | for (i = 0; i < MAX_DMA_CHANNELS; ++i) { |
38 | struct dma_register *dma = dma_io_base_addr[i]; | 40 | struct dma_register *dma = dma_io_base_addr[i]; |
@@ -93,4 +95,6 @@ void init_clocks(void) | |||
93 | #endif | 95 | #endif |
94 | do_sync(); | 96 | do_sync(); |
95 | bfin_read16(0); | 97 | bfin_read16(0); |
98 | |||
99 | #endif | ||
96 | } | 100 | } |
diff --git a/arch/blackfin/mach-common/cpufreq.c b/arch/blackfin/mach-common/cpufreq.c index 2e6eefd812f4..3b688797c78f 100644 --- a/arch/blackfin/mach-common/cpufreq.c +++ b/arch/blackfin/mach-common/cpufreq.c | |||
@@ -10,6 +10,7 @@ | |||
10 | #include <linux/module.h> | 10 | #include <linux/module.h> |
11 | #include <linux/types.h> | 11 | #include <linux/types.h> |
12 | #include <linux/init.h> | 12 | #include <linux/init.h> |
13 | #include <linux/clk.h> | ||
13 | #include <linux/cpufreq.h> | 14 | #include <linux/cpufreq.h> |
14 | #include <linux/fs.h> | 15 | #include <linux/fs.h> |
15 | #include <linux/delay.h> | 16 | #include <linux/delay.h> |
@@ -17,6 +18,7 @@ | |||
17 | #include <asm/time.h> | 18 | #include <asm/time.h> |
18 | #include <asm/dpmc.h> | 19 | #include <asm/dpmc.h> |
19 | 20 | ||
21 | |||
20 | /* this is the table of CCLK frequencies, in Hz */ | 22 | /* this is the table of CCLK frequencies, in Hz */ |
21 | /* .index is the entry in the auxiliary dpm_state_table[] */ | 23 | /* .index is the entry in the auxiliary dpm_state_table[] */ |
22 | static struct cpufreq_frequency_table bfin_freq_table[] = { | 24 | static struct cpufreq_frequency_table bfin_freq_table[] = { |
@@ -67,12 +69,22 @@ static void __init bfin_init_tables(unsigned long cclk, unsigned long sclk) | |||
67 | #else | 69 | #else |
68 | min_cclk = sclk; | 70 | min_cclk = sclk; |
69 | #endif | 71 | #endif |
72 | |||
73 | #ifndef CONFIG_BF60x | ||
70 | csel = ((bfin_read_PLL_DIV() & CSEL) >> 4); | 74 | csel = ((bfin_read_PLL_DIV() & CSEL) >> 4); |
75 | #else | ||
76 | csel = bfin_read32(CGU0_DIV) & 0x1F; | ||
77 | #endif | ||
71 | 78 | ||
72 | for (index = 0; (cclk >> index) >= min_cclk && csel <= 3; index++, csel++) { | 79 | for (index = 0; (cclk >> index) >= min_cclk && csel <= 3; index++, csel++) { |
73 | bfin_freq_table[index].frequency = cclk >> index; | 80 | bfin_freq_table[index].frequency = cclk >> index; |
81 | #ifndef CONFIG_BF60x | ||
74 | dpm_state_table[index].csel = csel << 4; /* Shift now into PLL_DIV bitpos */ | 82 | dpm_state_table[index].csel = csel << 4; /* Shift now into PLL_DIV bitpos */ |
75 | dpm_state_table[index].tscale = (TIME_SCALE / (1 << csel)) - 1; | 83 | dpm_state_table[index].tscale = (TIME_SCALE / (1 << csel)) - 1; |
84 | #else | ||
85 | dpm_state_table[index].csel = csel; | ||
86 | dpm_state_table[index].tscale = TIME_SCALE >> index; | ||
87 | #endif | ||
76 | 88 | ||
77 | pr_debug("cpufreq: freq:%d csel:0x%x tscale:%d\n", | 89 | pr_debug("cpufreq: freq:%d csel:0x%x tscale:%d\n", |
78 | bfin_freq_table[index].frequency, | 90 | bfin_freq_table[index].frequency, |
@@ -99,6 +111,20 @@ static unsigned int bfin_getfreq_khz(unsigned int cpu) | |||
99 | return get_cclk() / 1000; | 111 | return get_cclk() / 1000; |
100 | } | 112 | } |
101 | 113 | ||
114 | unsigned long cpu_set_cclk(int cpu, unsigned long new) | ||
115 | { | ||
116 | struct clk *clk; | ||
117 | int ret; | ||
118 | |||
119 | clk = clk_get(NULL, "CCLK"); | ||
120 | if (IS_ERR(clk)) | ||
121 | return -ENODEV; | ||
122 | |||
123 | ret = clk_set_rate(clk, new); | ||
124 | clk_put(clk); | ||
125 | return ret; | ||
126 | } | ||
127 | |||
102 | static int bfin_target(struct cpufreq_policy *poli, | 128 | static int bfin_target(struct cpufreq_policy *poli, |
103 | unsigned int target_freq, unsigned int relation) | 129 | unsigned int target_freq, unsigned int relation) |
104 | { | 130 | { |
@@ -107,6 +133,7 @@ static int bfin_target(struct cpufreq_policy *poli, | |||
107 | struct cpufreq_freqs freqs; | 133 | struct cpufreq_freqs freqs; |
108 | static unsigned long lpj_ref; | 134 | static unsigned long lpj_ref; |
109 | static unsigned int lpj_ref_freq; | 135 | static unsigned int lpj_ref_freq; |
136 | int ret = 0; | ||
110 | 137 | ||
111 | #if defined(CONFIG_CYCLES_CLOCKSOURCE) | 138 | #if defined(CONFIG_CYCLES_CLOCKSOURCE) |
112 | cycles_t cycles; | 139 | cycles_t cycles; |
@@ -134,9 +161,17 @@ static int bfin_target(struct cpufreq_policy *poli, | |||
134 | cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); | 161 | cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); |
135 | if (cpu == CPUFREQ_CPU) { | 162 | if (cpu == CPUFREQ_CPU) { |
136 | flags = hard_local_irq_save(); | 163 | flags = hard_local_irq_save(); |
164 | #ifndef CONFIG_BF60x | ||
137 | plldiv = (bfin_read_PLL_DIV() & SSEL) | | 165 | plldiv = (bfin_read_PLL_DIV() & SSEL) | |
138 | dpm_state_table[index].csel; | 166 | dpm_state_table[index].csel; |
139 | bfin_write_PLL_DIV(plldiv); | 167 | bfin_write_PLL_DIV(plldiv); |
168 | #else | ||
169 | ret = cpu_set_cclk(cpu, freqs.new * 1000); | ||
170 | if (ret != 0) { | ||
171 | pr_debug("cpufreq set freq failed %d\n", ret); | ||
172 | break; | ||
173 | } | ||
174 | #endif | ||
140 | on_each_cpu(bfin_adjust_core_timer, &index, 1); | 175 | on_each_cpu(bfin_adjust_core_timer, &index, 1); |
141 | #if defined(CONFIG_CYCLES_CLOCKSOURCE) | 176 | #if defined(CONFIG_CYCLES_CLOCKSOURCE) |
142 | cycles = get_cycles(); | 177 | cycles = get_cycles(); |
@@ -161,7 +196,7 @@ static int bfin_target(struct cpufreq_policy *poli, | |||
161 | } | 196 | } |
162 | 197 | ||
163 | pr_debug("cpufreq: done\n"); | 198 | pr_debug("cpufreq: done\n"); |
164 | return 0; | 199 | return ret; |
165 | } | 200 | } |
166 | 201 | ||
167 | static int bfin_verify_speed(struct cpufreq_policy *policy) | 202 | static int bfin_verify_speed(struct cpufreq_policy *policy) |
@@ -169,7 +204,7 @@ static int bfin_verify_speed(struct cpufreq_policy *policy) | |||
169 | return cpufreq_frequency_table_verify(policy, bfin_freq_table); | 204 | return cpufreq_frequency_table_verify(policy, bfin_freq_table); |
170 | } | 205 | } |
171 | 206 | ||
172 | static int __init __bfin_cpu_init(struct cpufreq_policy *policy) | 207 | static int __bfin_cpu_init(struct cpufreq_policy *policy) |
173 | { | 208 | { |
174 | 209 | ||
175 | unsigned long cclk, sclk; | 210 | unsigned long cclk, sclk; |