Root/
1 | /* |
2 | * Clock tree for CSR SiRFprimaII |
3 | * |
4 | * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company. |
5 | * |
6 | * Licensed under GPLv2 or later. |
7 | */ |
8 | |
9 | #include <linux/module.h> |
10 | #include <linux/bitops.h> |
11 | #include <linux/io.h> |
12 | #include <linux/clk.h> |
13 | #include <linux/clkdev.h> |
14 | #include <linux/clk-provider.h> |
15 | #include <linux/of_address.h> |
16 | #include <linux/syscore_ops.h> |
17 | |
18 | #define SIRFSOC_CLKC_CLK_EN0 0x0000 |
19 | #define SIRFSOC_CLKC_CLK_EN1 0x0004 |
20 | #define SIRFSOC_CLKC_REF_CFG 0x0014 |
21 | #define SIRFSOC_CLKC_CPU_CFG 0x0018 |
22 | #define SIRFSOC_CLKC_MEM_CFG 0x001c |
23 | #define SIRFSOC_CLKC_SYS_CFG 0x0020 |
24 | #define SIRFSOC_CLKC_IO_CFG 0x0024 |
25 | #define SIRFSOC_CLKC_DSP_CFG 0x0028 |
26 | #define SIRFSOC_CLKC_GFX_CFG 0x002c |
27 | #define SIRFSOC_CLKC_MM_CFG 0x0030 |
28 | #define SIRFSOC_CLKC_LCD_CFG 0x0034 |
29 | #define SIRFSOC_CLKC_MMC_CFG 0x0038 |
30 | #define SIRFSOC_CLKC_PLL1_CFG0 0x0040 |
31 | #define SIRFSOC_CLKC_PLL2_CFG0 0x0044 |
32 | #define SIRFSOC_CLKC_PLL3_CFG0 0x0048 |
33 | #define SIRFSOC_CLKC_PLL1_CFG1 0x004c |
34 | #define SIRFSOC_CLKC_PLL2_CFG1 0x0050 |
35 | #define SIRFSOC_CLKC_PLL3_CFG1 0x0054 |
36 | #define SIRFSOC_CLKC_PLL1_CFG2 0x0058 |
37 | #define SIRFSOC_CLKC_PLL2_CFG2 0x005c |
38 | #define SIRFSOC_CLKC_PLL3_CFG2 0x0060 |
39 | #define SIRFSOC_USBPHY_PLL_CTRL 0x0008 |
40 | #define SIRFSOC_USBPHY_PLL_POWERDOWN BIT(1) |
41 | #define SIRFSOC_USBPHY_PLL_BYPASS BIT(2) |
42 | #define SIRFSOC_USBPHY_PLL_LOCK BIT(3) |
43 | |
44 | static void *sirfsoc_clk_vbase, *sirfsoc_rsc_vbase; |
45 | |
46 | #define KHZ 1000 |
47 | #define MHZ (KHZ * KHZ) |
48 | |
49 | /* |
50 | * SiRFprimaII clock controller |
51 | * - 2 oscillators: osc-26MHz, rtc-32.768KHz |
52 | * - 3 standard configurable plls: pll1, pll2 & pll3 |
53 | * - 2 exclusive plls: usb phy pll and sata phy pll |
54 | * - 8 clock domains: cpu/cpudiv, mem/memdiv, sys/io, dsp, graphic, multimedia, |
55 | * display and sdphy. |
56 | * Each clock domain can select its own clock source from five clock sources, |
57 | * X_XIN, X_XINW, PLL1, PLL2 and PLL3. The domain clock is used as the source |
58 | * clock of the group clock. |
59 | * - dsp domain: gps, mf |
60 | * - io domain: dmac, nand, audio, uart, i2c, spi, usp, pwm, pulse |
61 | * - sys domain: security |
62 | */ |
63 | |
64 | struct clk_pll { |
65 | struct clk_hw hw; |
66 | unsigned short regofs; /* register offset */ |
67 | }; |
68 | |
69 | #define to_pllclk(_hw) container_of(_hw, struct clk_pll, hw) |
70 | |
71 | struct clk_dmn { |
72 | struct clk_hw hw; |
73 | signed char enable_bit; /* enable bit: 0 ~ 63 */ |
74 | unsigned short regofs; /* register offset */ |
75 | }; |
76 | |
77 | #define to_dmnclk(_hw) container_of(_hw, struct clk_dmn, hw) |
78 | |
79 | struct clk_std { |
80 | struct clk_hw hw; |
81 | signed char enable_bit; /* enable bit: 0 ~ 63 */ |
82 | }; |
83 | |
84 | #define to_stdclk(_hw) container_of(_hw, struct clk_std, hw) |
85 | |
86 | static int std_clk_is_enabled(struct clk_hw *hw); |
87 | static int std_clk_enable(struct clk_hw *hw); |
88 | static void std_clk_disable(struct clk_hw *hw); |
89 | |
90 | static inline unsigned long clkc_readl(unsigned reg) |
91 | { |
92 | return readl(sirfsoc_clk_vbase + reg); |
93 | } |
94 | |
95 | static inline void clkc_writel(u32 val, unsigned reg) |
96 | { |
97 | writel(val, sirfsoc_clk_vbase + reg); |
98 | } |
99 | |
100 | /* |
101 | * std pll |
102 | */ |
103 | |
104 | static unsigned long pll_clk_recalc_rate(struct clk_hw *hw, |
105 | unsigned long parent_rate) |
106 | { |
107 | unsigned long fin = parent_rate; |
108 | struct clk_pll *clk = to_pllclk(hw); |
109 | u32 regcfg2 = clk->regofs + SIRFSOC_CLKC_PLL1_CFG2 - |
110 | SIRFSOC_CLKC_PLL1_CFG0; |
111 | |
112 | if (clkc_readl(regcfg2) & BIT(2)) { |
113 | /* pll bypass mode */ |
114 | return fin; |
115 | } else { |
116 | /* fout = fin * nf / nr / od */ |
117 | u32 cfg0 = clkc_readl(clk->regofs); |
118 | u32 nf = (cfg0 & (BIT(13) - 1)) + 1; |
119 | u32 nr = ((cfg0 >> 13) & (BIT(6) - 1)) + 1; |
120 | u32 od = ((cfg0 >> 19) & (BIT(4) - 1)) + 1; |
121 | WARN_ON(fin % MHZ); |
122 | return fin / MHZ * nf / nr / od * MHZ; |
123 | } |
124 | } |
125 | |
126 | static long pll_clk_round_rate(struct clk_hw *hw, unsigned long rate, |
127 | unsigned long *parent_rate) |
128 | { |
129 | unsigned long fin, nf, nr, od; |
130 | |
131 | /* |
132 | * fout = fin * nf / (nr * od); |
133 | * set od = 1, nr = fin/MHz, so fout = nf * MHz |
134 | */ |
135 | rate = rate - rate % MHZ; |
136 | |
137 | nf = rate / MHZ; |
138 | if (nf > BIT(13)) |
139 | nf = BIT(13); |
140 | if (nf < 1) |
141 | nf = 1; |
142 | |
143 | fin = *parent_rate; |
144 | |
145 | nr = fin / MHZ; |
146 | if (nr > BIT(6)) |
147 | nr = BIT(6); |
148 | od = 1; |
149 | |
150 | return fin * nf / (nr * od); |
151 | } |
152 | |
153 | static int pll_clk_set_rate(struct clk_hw *hw, unsigned long rate, |
154 | unsigned long parent_rate) |
155 | { |
156 | struct clk_pll *clk = to_pllclk(hw); |
157 | unsigned long fin, nf, nr, od, reg; |
158 | |
159 | /* |
160 | * fout = fin * nf / (nr * od); |
161 | * set od = 1, nr = fin/MHz, so fout = nf * MHz |
162 | */ |
163 | |
164 | nf = rate / MHZ; |
165 | if (unlikely((rate % MHZ) || nf > BIT(13) || nf < 1)) |
166 | return -EINVAL; |
167 | |
168 | fin = parent_rate; |
169 | BUG_ON(fin < MHZ); |
170 | |
171 | nr = fin / MHZ; |
172 | BUG_ON((fin % MHZ) || nr > BIT(6)); |
173 | |
174 | od = 1; |
175 | |
176 | reg = (nf - 1) | ((nr - 1) << 13) | ((od - 1) << 19); |
177 | clkc_writel(reg, clk->regofs); |
178 | |
179 | reg = clk->regofs + SIRFSOC_CLKC_PLL1_CFG1 - SIRFSOC_CLKC_PLL1_CFG0; |
180 | clkc_writel((nf >> 1) - 1, reg); |
181 | |
182 | reg = clk->regofs + SIRFSOC_CLKC_PLL1_CFG2 - SIRFSOC_CLKC_PLL1_CFG0; |
183 | while (!(clkc_readl(reg) & BIT(6))) |
184 | cpu_relax(); |
185 | |
186 | return 0; |
187 | } |
188 | |
189 | static struct clk_ops std_pll_ops = { |
190 | .recalc_rate = pll_clk_recalc_rate, |
191 | .round_rate = pll_clk_round_rate, |
192 | .set_rate = pll_clk_set_rate, |
193 | }; |
194 | |
195 | static const char *pll_clk_parents[] = { |
196 | "osc", |
197 | }; |
198 | |
199 | static struct clk_init_data clk_pll1_init = { |
200 | .name = "pll1", |
201 | .ops = &std_pll_ops, |
202 | .parent_names = pll_clk_parents, |
203 | .num_parents = ARRAY_SIZE(pll_clk_parents), |
204 | }; |
205 | |
206 | static struct clk_init_data clk_pll2_init = { |
207 | .name = "pll2", |
208 | .ops = &std_pll_ops, |
209 | .parent_names = pll_clk_parents, |
210 | .num_parents = ARRAY_SIZE(pll_clk_parents), |
211 | }; |
212 | |
213 | static struct clk_init_data clk_pll3_init = { |
214 | .name = "pll3", |
215 | .ops = &std_pll_ops, |
216 | .parent_names = pll_clk_parents, |
217 | .num_parents = ARRAY_SIZE(pll_clk_parents), |
218 | }; |
219 | |
220 | static struct clk_pll clk_pll1 = { |
221 | .regofs = SIRFSOC_CLKC_PLL1_CFG0, |
222 | .hw = { |
223 | .init = &clk_pll1_init, |
224 | }, |
225 | }; |
226 | |
227 | static struct clk_pll clk_pll2 = { |
228 | .regofs = SIRFSOC_CLKC_PLL2_CFG0, |
229 | .hw = { |
230 | .init = &clk_pll2_init, |
231 | }, |
232 | }; |
233 | |
234 | static struct clk_pll clk_pll3 = { |
235 | .regofs = SIRFSOC_CLKC_PLL3_CFG0, |
236 | .hw = { |
237 | .init = &clk_pll3_init, |
238 | }, |
239 | }; |
240 | |
241 | /* |
242 | * usb uses specified pll |
243 | */ |
244 | |
245 | static int usb_pll_clk_enable(struct clk_hw *hw) |
246 | { |
247 | u32 reg = readl(sirfsoc_rsc_vbase + SIRFSOC_USBPHY_PLL_CTRL); |
248 | reg &= ~(SIRFSOC_USBPHY_PLL_POWERDOWN | SIRFSOC_USBPHY_PLL_BYPASS); |
249 | writel(reg, sirfsoc_rsc_vbase + SIRFSOC_USBPHY_PLL_CTRL); |
250 | while (!(readl(sirfsoc_rsc_vbase + SIRFSOC_USBPHY_PLL_CTRL) & |
251 | SIRFSOC_USBPHY_PLL_LOCK)) |
252 | cpu_relax(); |
253 | |
254 | return 0; |
255 | } |
256 | |
257 | static void usb_pll_clk_disable(struct clk_hw *clk) |
258 | { |
259 | u32 reg = readl(sirfsoc_rsc_vbase + SIRFSOC_USBPHY_PLL_CTRL); |
260 | reg |= (SIRFSOC_USBPHY_PLL_POWERDOWN | SIRFSOC_USBPHY_PLL_BYPASS); |
261 | writel(reg, sirfsoc_rsc_vbase + SIRFSOC_USBPHY_PLL_CTRL); |
262 | } |
263 | |
264 | static unsigned long usb_pll_clk_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) |
265 | { |
266 | u32 reg = readl(sirfsoc_rsc_vbase + SIRFSOC_USBPHY_PLL_CTRL); |
267 | return (reg & SIRFSOC_USBPHY_PLL_BYPASS) ? parent_rate : 48*MHZ; |
268 | } |
269 | |
270 | static struct clk_ops usb_pll_ops = { |
271 | .enable = usb_pll_clk_enable, |
272 | .disable = usb_pll_clk_disable, |
273 | .recalc_rate = usb_pll_clk_recalc_rate, |
274 | }; |
275 | |
276 | static struct clk_init_data clk_usb_pll_init = { |
277 | .name = "usb_pll", |
278 | .ops = &usb_pll_ops, |
279 | .parent_names = pll_clk_parents, |
280 | .num_parents = ARRAY_SIZE(pll_clk_parents), |
281 | }; |
282 | |
283 | static struct clk_hw usb_pll_clk_hw = { |
284 | .init = &clk_usb_pll_init, |
285 | }; |
286 | |
287 | /* |
288 | * clock domains - cpu, mem, sys/io, dsp, gfx |
289 | */ |
290 | |
291 | static const char *dmn_clk_parents[] = { |
292 | "rtc", |
293 | "osc", |
294 | "pll1", |
295 | "pll2", |
296 | "pll3", |
297 | }; |
298 | |
299 | static u8 dmn_clk_get_parent(struct clk_hw *hw) |
300 | { |
301 | struct clk_dmn *clk = to_dmnclk(hw); |
302 | u32 cfg = clkc_readl(clk->regofs); |
303 | |
304 | /* parent of io domain can only be pll3 */ |
305 | if (strcmp(hw->init->name, "io") == 0) |
306 | return 4; |
307 | |
308 | WARN_ON((cfg & (BIT(3) - 1)) > 4); |
309 | |
310 | return cfg & (BIT(3) - 1); |
311 | } |
312 | |
313 | static int dmn_clk_set_parent(struct clk_hw *hw, u8 parent) |
314 | { |
315 | struct clk_dmn *clk = to_dmnclk(hw); |
316 | u32 cfg = clkc_readl(clk->regofs); |
317 | |
318 | /* parent of io domain can only be pll3 */ |
319 | if (strcmp(hw->init->name, "io") == 0) |
320 | return -EINVAL; |
321 | |
322 | cfg &= ~(BIT(3) - 1); |
323 | clkc_writel(cfg | parent, clk->regofs); |
324 | /* BIT(3) - switching status: 1 - busy, 0 - done */ |
325 | while (clkc_readl(clk->regofs) & BIT(3)) |
326 | cpu_relax(); |
327 | |
328 | return 0; |
329 | } |
330 | |
331 | static unsigned long dmn_clk_recalc_rate(struct clk_hw *hw, |
332 | unsigned long parent_rate) |
333 | |
334 | { |
335 | unsigned long fin = parent_rate; |
336 | struct clk_dmn *clk = to_dmnclk(hw); |
337 | |
338 | u32 cfg = clkc_readl(clk->regofs); |
339 | |
340 | if (cfg & BIT(24)) { |
341 | /* fcd bypass mode */ |
342 | return fin; |
343 | } else { |
344 | /* |
345 | * wait count: bit[19:16], hold count: bit[23:20] |
346 | */ |
347 | u32 wait = (cfg >> 16) & (BIT(4) - 1); |
348 | u32 hold = (cfg >> 20) & (BIT(4) - 1); |
349 | |
350 | return fin / (wait + hold + 2); |
351 | } |
352 | } |
353 | |
354 | static long dmn_clk_round_rate(struct clk_hw *hw, unsigned long rate, |
355 | unsigned long *parent_rate) |
356 | { |
357 | unsigned long fin; |
358 | unsigned ratio, wait, hold; |
359 | unsigned bits = (strcmp(hw->init->name, "mem") == 0) ? 3 : 4; |
360 | |
361 | fin = *parent_rate; |
362 | ratio = fin / rate; |
363 | |
364 | if (ratio < 2) |
365 | ratio = 2; |
366 | if (ratio > BIT(bits + 1)) |
367 | ratio = BIT(bits + 1); |
368 | |
369 | wait = (ratio >> 1) - 1; |
370 | hold = ratio - wait - 2; |
371 | |
372 | return fin / (wait + hold + 2); |
373 | } |
374 | |
375 | static int dmn_clk_set_rate(struct clk_hw *hw, unsigned long rate, |
376 | unsigned long parent_rate) |
377 | { |
378 | struct clk_dmn *clk = to_dmnclk(hw); |
379 | unsigned long fin; |
380 | unsigned ratio, wait, hold, reg; |
381 | unsigned bits = (strcmp(hw->init->name, "mem") == 0) ? 3 : 4; |
382 | |
383 | fin = parent_rate; |
384 | ratio = fin / rate; |
385 | |
386 | if (unlikely(ratio < 2 || ratio > BIT(bits + 1))) |
387 | return -EINVAL; |
388 | |
389 | WARN_ON(fin % rate); |
390 | |
391 | wait = (ratio >> 1) - 1; |
392 | hold = ratio - wait - 2; |
393 | |
394 | reg = clkc_readl(clk->regofs); |
395 | reg &= ~(((BIT(bits) - 1) << 16) | ((BIT(bits) - 1) << 20)); |
396 | reg |= (wait << 16) | (hold << 20) | BIT(25); |
397 | clkc_writel(reg, clk->regofs); |
398 | |
399 | /* waiting FCD been effective */ |
400 | while (clkc_readl(clk->regofs) & BIT(25)) |
401 | cpu_relax(); |
402 | |
403 | return 0; |
404 | } |
405 | |
406 | static struct clk_ops msi_ops = { |
407 | .set_rate = dmn_clk_set_rate, |
408 | .round_rate = dmn_clk_round_rate, |
409 | .recalc_rate = dmn_clk_recalc_rate, |
410 | .set_parent = dmn_clk_set_parent, |
411 | .get_parent = dmn_clk_get_parent, |
412 | }; |
413 | |
414 | static struct clk_init_data clk_mem_init = { |
415 | .name = "mem", |
416 | .ops = &msi_ops, |
417 | .parent_names = dmn_clk_parents, |
418 | .num_parents = ARRAY_SIZE(dmn_clk_parents), |
419 | }; |
420 | |
421 | static struct clk_dmn clk_mem = { |
422 | .regofs = SIRFSOC_CLKC_MEM_CFG, |
423 | .hw = { |
424 | .init = &clk_mem_init, |
425 | }, |
426 | }; |
427 | |
428 | static struct clk_init_data clk_sys_init = { |
429 | .name = "sys", |
430 | .ops = &msi_ops, |
431 | .parent_names = dmn_clk_parents, |
432 | .num_parents = ARRAY_SIZE(dmn_clk_parents), |
433 | .flags = CLK_SET_RATE_GATE, |
434 | }; |
435 | |
436 | static struct clk_dmn clk_sys = { |
437 | .regofs = SIRFSOC_CLKC_SYS_CFG, |
438 | .hw = { |
439 | .init = &clk_sys_init, |
440 | }, |
441 | }; |
442 | |
443 | static struct clk_init_data clk_io_init = { |
444 | .name = "io", |
445 | .ops = &msi_ops, |
446 | .parent_names = dmn_clk_parents, |
447 | .num_parents = ARRAY_SIZE(dmn_clk_parents), |
448 | }; |
449 | |
450 | static struct clk_dmn clk_io = { |
451 | .regofs = SIRFSOC_CLKC_IO_CFG, |
452 | .hw = { |
453 | .init = &clk_io_init, |
454 | }, |
455 | }; |
456 | |
457 | static struct clk_ops cpu_ops = { |
458 | .set_parent = dmn_clk_set_parent, |
459 | .get_parent = dmn_clk_get_parent, |
460 | }; |
461 | |
462 | static struct clk_init_data clk_cpu_init = { |
463 | .name = "cpu", |
464 | .ops = &cpu_ops, |
465 | .parent_names = dmn_clk_parents, |
466 | .num_parents = ARRAY_SIZE(dmn_clk_parents), |
467 | .flags = CLK_SET_RATE_PARENT, |
468 | }; |
469 | |
470 | static struct clk_dmn clk_cpu = { |
471 | .regofs = SIRFSOC_CLKC_CPU_CFG, |
472 | .hw = { |
473 | .init = &clk_cpu_init, |
474 | }, |
475 | }; |
476 | |
477 | static struct clk_ops dmn_ops = { |
478 | .is_enabled = std_clk_is_enabled, |
479 | .enable = std_clk_enable, |
480 | .disable = std_clk_disable, |
481 | .set_rate = dmn_clk_set_rate, |
482 | .round_rate = dmn_clk_round_rate, |
483 | .recalc_rate = dmn_clk_recalc_rate, |
484 | .set_parent = dmn_clk_set_parent, |
485 | .get_parent = dmn_clk_get_parent, |
486 | }; |
487 | |
488 | /* dsp, gfx, mm, lcd and vpp domain */ |
489 | |
490 | static struct clk_init_data clk_dsp_init = { |
491 | .name = "dsp", |
492 | .ops = &dmn_ops, |
493 | .parent_names = dmn_clk_parents, |
494 | .num_parents = ARRAY_SIZE(dmn_clk_parents), |
495 | }; |
496 | |
497 | static struct clk_dmn clk_dsp = { |
498 | .regofs = SIRFSOC_CLKC_DSP_CFG, |
499 | .enable_bit = 0, |
500 | .hw = { |
501 | .init = &clk_dsp_init, |
502 | }, |
503 | }; |
504 | |
505 | static struct clk_init_data clk_gfx_init = { |
506 | .name = "gfx", |
507 | .ops = &dmn_ops, |
508 | .parent_names = dmn_clk_parents, |
509 | .num_parents = ARRAY_SIZE(dmn_clk_parents), |
510 | }; |
511 | |
512 | static struct clk_dmn clk_gfx = { |
513 | .regofs = SIRFSOC_CLKC_GFX_CFG, |
514 | .enable_bit = 8, |
515 | .hw = { |
516 | .init = &clk_gfx_init, |
517 | }, |
518 | }; |
519 | |
520 | static struct clk_init_data clk_mm_init = { |
521 | .name = "mm", |
522 | .ops = &dmn_ops, |
523 | .parent_names = dmn_clk_parents, |
524 | .num_parents = ARRAY_SIZE(dmn_clk_parents), |
525 | }; |
526 | |
527 | static struct clk_dmn clk_mm = { |
528 | .regofs = SIRFSOC_CLKC_MM_CFG, |
529 | .enable_bit = 9, |
530 | .hw = { |
531 | .init = &clk_mm_init, |
532 | }, |
533 | }; |
534 | |
535 | static struct clk_init_data clk_lcd_init = { |
536 | .name = "lcd", |
537 | .ops = &dmn_ops, |
538 | .parent_names = dmn_clk_parents, |
539 | .num_parents = ARRAY_SIZE(dmn_clk_parents), |
540 | }; |
541 | |
542 | static struct clk_dmn clk_lcd = { |
543 | .regofs = SIRFSOC_CLKC_LCD_CFG, |
544 | .enable_bit = 10, |
545 | .hw = { |
546 | .init = &clk_lcd_init, |
547 | }, |
548 | }; |
549 | |
550 | static struct clk_init_data clk_vpp_init = { |
551 | .name = "vpp", |
552 | .ops = &dmn_ops, |
553 | .parent_names = dmn_clk_parents, |
554 | .num_parents = ARRAY_SIZE(dmn_clk_parents), |
555 | }; |
556 | |
557 | static struct clk_dmn clk_vpp = { |
558 | .regofs = SIRFSOC_CLKC_LCD_CFG, |
559 | .enable_bit = 11, |
560 | .hw = { |
561 | .init = &clk_vpp_init, |
562 | }, |
563 | }; |
564 | |
565 | static struct clk_init_data clk_mmc01_init = { |
566 | .name = "mmc01", |
567 | .ops = &dmn_ops, |
568 | .parent_names = dmn_clk_parents, |
569 | .num_parents = ARRAY_SIZE(dmn_clk_parents), |
570 | }; |
571 | |
572 | static struct clk_dmn clk_mmc01 = { |
573 | .regofs = SIRFSOC_CLKC_MMC_CFG, |
574 | .enable_bit = 59, |
575 | .hw = { |
576 | .init = &clk_mmc01_init, |
577 | }, |
578 | }; |
579 | |
580 | static struct clk_init_data clk_mmc23_init = { |
581 | .name = "mmc23", |
582 | .ops = &dmn_ops, |
583 | .parent_names = dmn_clk_parents, |
584 | .num_parents = ARRAY_SIZE(dmn_clk_parents), |
585 | }; |
586 | |
587 | static struct clk_dmn clk_mmc23 = { |
588 | .regofs = SIRFSOC_CLKC_MMC_CFG, |
589 | .enable_bit = 60, |
590 | .hw = { |
591 | .init = &clk_mmc23_init, |
592 | }, |
593 | }; |
594 | |
595 | static struct clk_init_data clk_mmc45_init = { |
596 | .name = "mmc45", |
597 | .ops = &dmn_ops, |
598 | .parent_names = dmn_clk_parents, |
599 | .num_parents = ARRAY_SIZE(dmn_clk_parents), |
600 | }; |
601 | |
602 | static struct clk_dmn clk_mmc45 = { |
603 | .regofs = SIRFSOC_CLKC_MMC_CFG, |
604 | .enable_bit = 61, |
605 | .hw = { |
606 | .init = &clk_mmc45_init, |
607 | }, |
608 | }; |
609 | |
610 | /* |
611 | * peripheral controllers in io domain |
612 | */ |
613 | |
614 | static int std_clk_is_enabled(struct clk_hw *hw) |
615 | { |
616 | u32 reg; |
617 | int bit; |
618 | struct clk_std *clk = to_stdclk(hw); |
619 | |
620 | bit = clk->enable_bit % 32; |
621 | reg = clk->enable_bit / 32; |
622 | reg = SIRFSOC_CLKC_CLK_EN0 + reg * sizeof(reg); |
623 | |
624 | return !!(clkc_readl(reg) & BIT(bit)); |
625 | } |
626 | |
627 | static int std_clk_enable(struct clk_hw *hw) |
628 | { |
629 | u32 val, reg; |
630 | int bit; |
631 | struct clk_std *clk = to_stdclk(hw); |
632 | |
633 | BUG_ON(clk->enable_bit < 0 || clk->enable_bit > 63); |
634 | |
635 | bit = clk->enable_bit % 32; |
636 | reg = clk->enable_bit / 32; |
637 | reg = SIRFSOC_CLKC_CLK_EN0 + reg * sizeof(reg); |
638 | |
639 | val = clkc_readl(reg) | BIT(bit); |
640 | clkc_writel(val, reg); |
641 | return 0; |
642 | } |
643 | |
644 | static void std_clk_disable(struct clk_hw *hw) |
645 | { |
646 | u32 val, reg; |
647 | int bit; |
648 | struct clk_std *clk = to_stdclk(hw); |
649 | |
650 | BUG_ON(clk->enable_bit < 0 || clk->enable_bit > 63); |
651 | |
652 | bit = clk->enable_bit % 32; |
653 | reg = clk->enable_bit / 32; |
654 | reg = SIRFSOC_CLKC_CLK_EN0 + reg * sizeof(reg); |
655 | |
656 | val = clkc_readl(reg) & ~BIT(bit); |
657 | clkc_writel(val, reg); |
658 | } |
659 | |
660 | static const char *std_clk_io_parents[] = { |
661 | "io", |
662 | }; |
663 | |
664 | static struct clk_ops ios_ops = { |
665 | .is_enabled = std_clk_is_enabled, |
666 | .enable = std_clk_enable, |
667 | .disable = std_clk_disable, |
668 | }; |
669 | |
670 | static struct clk_init_data clk_dmac0_init = { |
671 | .name = "dmac0", |
672 | .ops = &ios_ops, |
673 | .parent_names = std_clk_io_parents, |
674 | .num_parents = ARRAY_SIZE(std_clk_io_parents), |
675 | }; |
676 | |
677 | static struct clk_std clk_dmac0 = { |
678 | .enable_bit = 32, |
679 | .hw = { |
680 | .init = &clk_dmac0_init, |
681 | }, |
682 | }; |
683 | |
684 | static struct clk_init_data clk_dmac1_init = { |
685 | .name = "dmac1", |
686 | .ops = &ios_ops, |
687 | .parent_names = std_clk_io_parents, |
688 | .num_parents = ARRAY_SIZE(std_clk_io_parents), |
689 | }; |
690 | |
691 | static struct clk_std clk_dmac1 = { |
692 | .enable_bit = 33, |
693 | .hw = { |
694 | .init = &clk_dmac1_init, |
695 | }, |
696 | }; |
697 | |
698 | static struct clk_init_data clk_nand_init = { |
699 | .name = "nand", |
700 | .ops = &ios_ops, |
701 | .parent_names = std_clk_io_parents, |
702 | .num_parents = ARRAY_SIZE(std_clk_io_parents), |
703 | }; |
704 | |
705 | static struct clk_std clk_nand = { |
706 | .enable_bit = 34, |
707 | .hw = { |
708 | .init = &clk_nand_init, |
709 | }, |
710 | }; |
711 | |
712 | static struct clk_init_data clk_audio_init = { |
713 | .name = "audio", |
714 | .ops = &ios_ops, |
715 | .parent_names = std_clk_io_parents, |
716 | .num_parents = ARRAY_SIZE(std_clk_io_parents), |
717 | }; |
718 | |
719 | static struct clk_std clk_audio = { |
720 | .enable_bit = 35, |
721 | .hw = { |
722 | .init = &clk_audio_init, |
723 | }, |
724 | }; |
725 | |
726 | static struct clk_init_data clk_uart0_init = { |
727 | .name = "uart0", |
728 | .ops = &ios_ops, |
729 | .parent_names = std_clk_io_parents, |
730 | .num_parents = ARRAY_SIZE(std_clk_io_parents), |
731 | }; |
732 | |
733 | static struct clk_std clk_uart0 = { |
734 | .enable_bit = 36, |
735 | .hw = { |
736 | .init = &clk_uart0_init, |
737 | }, |
738 | }; |
739 | |
740 | static struct clk_init_data clk_uart1_init = { |
741 | .name = "uart1", |
742 | .ops = &ios_ops, |
743 | .parent_names = std_clk_io_parents, |
744 | .num_parents = ARRAY_SIZE(std_clk_io_parents), |
745 | }; |
746 | |
747 | static struct clk_std clk_uart1 = { |
748 | .enable_bit = 37, |
749 | .hw = { |
750 | .init = &clk_uart1_init, |
751 | }, |
752 | }; |
753 | |
754 | static struct clk_init_data clk_uart2_init = { |
755 | .name = "uart2", |
756 | .ops = &ios_ops, |
757 | .parent_names = std_clk_io_parents, |
758 | .num_parents = ARRAY_SIZE(std_clk_io_parents), |
759 | }; |
760 | |
761 | static struct clk_std clk_uart2 = { |
762 | .enable_bit = 38, |
763 | .hw = { |
764 | .init = &clk_uart2_init, |
765 | }, |
766 | }; |
767 | |
768 | static struct clk_init_data clk_usp0_init = { |
769 | .name = "usp0", |
770 | .ops = &ios_ops, |
771 | .parent_names = std_clk_io_parents, |
772 | .num_parents = ARRAY_SIZE(std_clk_io_parents), |
773 | }; |
774 | |
775 | static struct clk_std clk_usp0 = { |
776 | .enable_bit = 39, |
777 | .hw = { |
778 | .init = &clk_usp0_init, |
779 | }, |
780 | }; |
781 | |
782 | static struct clk_init_data clk_usp1_init = { |
783 | .name = "usp1", |
784 | .ops = &ios_ops, |
785 | .parent_names = std_clk_io_parents, |
786 | .num_parents = ARRAY_SIZE(std_clk_io_parents), |
787 | }; |
788 | |
789 | static struct clk_std clk_usp1 = { |
790 | .enable_bit = 40, |
791 | .hw = { |
792 | .init = &clk_usp1_init, |
793 | }, |
794 | }; |
795 | |
796 | static struct clk_init_data clk_usp2_init = { |
797 | .name = "usp2", |
798 | .ops = &ios_ops, |
799 | .parent_names = std_clk_io_parents, |
800 | .num_parents = ARRAY_SIZE(std_clk_io_parents), |
801 | }; |
802 | |
803 | static struct clk_std clk_usp2 = { |
804 | .enable_bit = 41, |
805 | .hw = { |
806 | .init = &clk_usp2_init, |
807 | }, |
808 | }; |
809 | |
810 | static struct clk_init_data clk_vip_init = { |
811 | .name = "vip", |
812 | .ops = &ios_ops, |
813 | .parent_names = std_clk_io_parents, |
814 | .num_parents = ARRAY_SIZE(std_clk_io_parents), |
815 | }; |
816 | |
817 | static struct clk_std clk_vip = { |
818 | .enable_bit = 42, |
819 | .hw = { |
820 | .init = &clk_vip_init, |
821 | }, |
822 | }; |
823 | |
824 | static struct clk_init_data clk_spi0_init = { |
825 | .name = "spi0", |
826 | .ops = &ios_ops, |
827 | .parent_names = std_clk_io_parents, |
828 | .num_parents = ARRAY_SIZE(std_clk_io_parents), |
829 | }; |
830 | |
831 | static struct clk_std clk_spi0 = { |
832 | .enable_bit = 43, |
833 | .hw = { |
834 | .init = &clk_spi0_init, |
835 | }, |
836 | }; |
837 | |
838 | static struct clk_init_data clk_spi1_init = { |
839 | .name = "spi1", |
840 | .ops = &ios_ops, |
841 | .parent_names = std_clk_io_parents, |
842 | .num_parents = ARRAY_SIZE(std_clk_io_parents), |
843 | }; |
844 | |
845 | static struct clk_std clk_spi1 = { |
846 | .enable_bit = 44, |
847 | .hw = { |
848 | .init = &clk_spi1_init, |
849 | }, |
850 | }; |
851 | |
852 | static struct clk_init_data clk_tsc_init = { |
853 | .name = "tsc", |
854 | .ops = &ios_ops, |
855 | .parent_names = std_clk_io_parents, |
856 | .num_parents = ARRAY_SIZE(std_clk_io_parents), |
857 | }; |
858 | |
859 | static struct clk_std clk_tsc = { |
860 | .enable_bit = 45, |
861 | .hw = { |
862 | .init = &clk_tsc_init, |
863 | }, |
864 | }; |
865 | |
866 | static struct clk_init_data clk_i2c0_init = { |
867 | .name = "i2c0", |
868 | .ops = &ios_ops, |
869 | .parent_names = std_clk_io_parents, |
870 | .num_parents = ARRAY_SIZE(std_clk_io_parents), |
871 | }; |
872 | |
873 | static struct clk_std clk_i2c0 = { |
874 | .enable_bit = 46, |
875 | .hw = { |
876 | .init = &clk_i2c0_init, |
877 | }, |
878 | }; |
879 | |
880 | static struct clk_init_data clk_i2c1_init = { |
881 | .name = "i2c1", |
882 | .ops = &ios_ops, |
883 | .parent_names = std_clk_io_parents, |
884 | .num_parents = ARRAY_SIZE(std_clk_io_parents), |
885 | }; |
886 | |
887 | static struct clk_std clk_i2c1 = { |
888 | .enable_bit = 47, |
889 | .hw = { |
890 | .init = &clk_i2c1_init, |
891 | }, |
892 | }; |
893 | |
894 | static struct clk_init_data clk_pwmc_init = { |
895 | .name = "pwmc", |
896 | .ops = &ios_ops, |
897 | .parent_names = std_clk_io_parents, |
898 | .num_parents = ARRAY_SIZE(std_clk_io_parents), |
899 | }; |
900 | |
901 | static struct clk_std clk_pwmc = { |
902 | .enable_bit = 48, |
903 | .hw = { |
904 | .init = &clk_pwmc_init, |
905 | }, |
906 | }; |
907 | |
908 | static struct clk_init_data clk_efuse_init = { |
909 | .name = "efuse", |
910 | .ops = &ios_ops, |
911 | .parent_names = std_clk_io_parents, |
912 | .num_parents = ARRAY_SIZE(std_clk_io_parents), |
913 | }; |
914 | |
915 | static struct clk_std clk_efuse = { |
916 | .enable_bit = 49, |
917 | .hw = { |
918 | .init = &clk_efuse_init, |
919 | }, |
920 | }; |
921 | |
922 | static struct clk_init_data clk_pulse_init = { |
923 | .name = "pulse", |
924 | .ops = &ios_ops, |
925 | .parent_names = std_clk_io_parents, |
926 | .num_parents = ARRAY_SIZE(std_clk_io_parents), |
927 | }; |
928 | |
929 | static struct clk_std clk_pulse = { |
930 | .enable_bit = 50, |
931 | .hw = { |
932 | .init = &clk_pulse_init, |
933 | }, |
934 | }; |
935 | |
936 | static const char *std_clk_dsp_parents[] = { |
937 | "dsp", |
938 | }; |
939 | |
940 | static struct clk_init_data clk_gps_init = { |
941 | .name = "gps", |
942 | .ops = &ios_ops, |
943 | .parent_names = std_clk_dsp_parents, |
944 | .num_parents = ARRAY_SIZE(std_clk_dsp_parents), |
945 | }; |
946 | |
947 | static struct clk_std clk_gps = { |
948 | .enable_bit = 1, |
949 | .hw = { |
950 | .init = &clk_gps_init, |
951 | }, |
952 | }; |
953 | |
954 | static struct clk_init_data clk_mf_init = { |
955 | .name = "mf", |
956 | .ops = &ios_ops, |
957 | .parent_names = std_clk_io_parents, |
958 | .num_parents = ARRAY_SIZE(std_clk_io_parents), |
959 | }; |
960 | |
961 | static struct clk_std clk_mf = { |
962 | .enable_bit = 2, |
963 | .hw = { |
964 | .init = &clk_mf_init, |
965 | }, |
966 | }; |
967 | |
968 | static const char *std_clk_sys_parents[] = { |
969 | "sys", |
970 | }; |
971 | |
972 | static struct clk_init_data clk_security_init = { |
973 | .name = "mf", |
974 | .ops = &ios_ops, |
975 | .parent_names = std_clk_sys_parents, |
976 | .num_parents = ARRAY_SIZE(std_clk_sys_parents), |
977 | }; |
978 | |
979 | static struct clk_std clk_security = { |
980 | .enable_bit = 19, |
981 | .hw = { |
982 | .init = &clk_security_init, |
983 | }, |
984 | }; |
985 | |
986 | static const char *std_clk_usb_parents[] = { |
987 | "usb_pll", |
988 | }; |
989 | |
990 | static struct clk_init_data clk_usb0_init = { |
991 | .name = "usb0", |
992 | .ops = &ios_ops, |
993 | .parent_names = std_clk_usb_parents, |
994 | .num_parents = ARRAY_SIZE(std_clk_usb_parents), |
995 | }; |
996 | |
997 | static struct clk_std clk_usb0 = { |
998 | .enable_bit = 16, |
999 | .hw = { |
1000 | .init = &clk_usb0_init, |
1001 | }, |
1002 | }; |
1003 | |
1004 | static struct clk_init_data clk_usb1_init = { |
1005 | .name = "usb1", |
1006 | .ops = &ios_ops, |
1007 | .parent_names = std_clk_usb_parents, |
1008 | .num_parents = ARRAY_SIZE(std_clk_usb_parents), |
1009 | }; |
1010 | |
1011 | static struct clk_std clk_usb1 = { |
1012 | .enable_bit = 17, |
1013 | .hw = { |
1014 | .init = &clk_usb1_init, |
1015 | }, |
1016 | }; |
1017 | |
1018 | static struct of_device_id clkc_ids[] = { |
1019 | { .compatible = "sirf,prima2-clkc" }, |
1020 | {}, |
1021 | }; |
1022 | |
1023 | static struct of_device_id rsc_ids[] = { |
1024 | { .compatible = "sirf,prima2-rsc" }, |
1025 | {}, |
1026 | }; |
1027 | |
1028 | enum prima2_clk_index { |
1029 | /* 0 1 2 3 4 5 6 7 8 9 */ |
1030 | rtc, osc, pll1, pll2, pll3, mem, sys, security, dsp, gps, |
1031 | mf, io, cpu, uart0, uart1, uart2, tsc, i2c0, i2c1, spi0, |
1032 | spi1, pwmc, efuse, pulse, dmac0, dmac1, nand, audio, usp0, usp1, |
1033 | usp2, vip, gfx, mm, lcd, vpp, mmc01, mmc23, mmc45, usbpll, |
1034 | usb0, usb1, maxclk, |
1035 | }; |
1036 | |
1037 | static __initdata struct clk_hw* prima2_clk_hw_array[maxclk] = { |
1038 | NULL, /* dummy */ |
1039 | NULL, |
1040 | &clk_pll1.hw, |
1041 | &clk_pll2.hw, |
1042 | &clk_pll3.hw, |
1043 | &clk_mem.hw, |
1044 | &clk_sys.hw, |
1045 | &clk_security.hw, |
1046 | &clk_dsp.hw, |
1047 | &clk_gps.hw, |
1048 | &clk_mf.hw, |
1049 | &clk_io.hw, |
1050 | &clk_cpu.hw, |
1051 | &clk_uart0.hw, |
1052 | &clk_uart1.hw, |
1053 | &clk_uart2.hw, |
1054 | &clk_tsc.hw, |
1055 | &clk_i2c0.hw, |
1056 | &clk_i2c1.hw, |
1057 | &clk_spi0.hw, |
1058 | &clk_spi1.hw, |
1059 | &clk_pwmc.hw, |
1060 | &clk_efuse.hw, |
1061 | &clk_pulse.hw, |
1062 | &clk_dmac0.hw, |
1063 | &clk_dmac1.hw, |
1064 | &clk_nand.hw, |
1065 | &clk_audio.hw, |
1066 | &clk_usp0.hw, |
1067 | &clk_usp1.hw, |
1068 | &clk_usp2.hw, |
1069 | &clk_vip.hw, |
1070 | &clk_gfx.hw, |
1071 | &clk_mm.hw, |
1072 | &clk_lcd.hw, |
1073 | &clk_vpp.hw, |
1074 | &clk_mmc01.hw, |
1075 | &clk_mmc23.hw, |
1076 | &clk_mmc45.hw, |
1077 | &usb_pll_clk_hw, |
1078 | &clk_usb0.hw, |
1079 | &clk_usb1.hw, |
1080 | }; |
1081 | |
1082 | static struct clk *prima2_clks[maxclk]; |
1083 | static struct clk_onecell_data clk_data; |
1084 | |
1085 | void __init sirfsoc_of_clk_init(void) |
1086 | { |
1087 | struct device_node *np; |
1088 | int i; |
1089 | |
1090 | np = of_find_matching_node(NULL, rsc_ids); |
1091 | if (!np) |
1092 | panic("unable to find compatible rsc node in dtb\n"); |
1093 | |
1094 | sirfsoc_rsc_vbase = of_iomap(np, 0); |
1095 | if (!sirfsoc_rsc_vbase) |
1096 | panic("unable to map rsc registers\n"); |
1097 | |
1098 | of_node_put(np); |
1099 | |
1100 | np = of_find_matching_node(NULL, clkc_ids); |
1101 | if (!np) |
1102 | return; |
1103 | |
1104 | sirfsoc_clk_vbase = of_iomap(np, 0); |
1105 | if (!sirfsoc_clk_vbase) |
1106 | panic("unable to map clkc registers\n"); |
1107 | |
1108 | /* These are always available (RTC and 26MHz OSC)*/ |
1109 | prima2_clks[rtc] = clk_register_fixed_rate(NULL, "rtc", NULL, |
1110 | CLK_IS_ROOT, 32768); |
1111 | prima2_clks[osc]= clk_register_fixed_rate(NULL, "osc", NULL, |
1112 | CLK_IS_ROOT, 26000000); |
1113 | |
1114 | for (i = pll1; i < maxclk; i++) { |
1115 | prima2_clks[i] = clk_register(NULL, prima2_clk_hw_array[i]); |
1116 | BUG_ON(!prima2_clks[i]); |
1117 | } |
1118 | clk_register_clkdev(prima2_clks[cpu], NULL, "cpu"); |
1119 | clk_register_clkdev(prima2_clks[io], NULL, "io"); |
1120 | clk_register_clkdev(prima2_clks[mem], NULL, "mem"); |
1121 | |
1122 | clk_data.clks = prima2_clks; |
1123 | clk_data.clk_num = maxclk; |
1124 | |
1125 | of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data); |
1126 | } |
1127 |
Branches:
ben-wpan
ben-wpan-stefan
javiroman/ks7010
jz-2.6.34
jz-2.6.34-rc5
jz-2.6.34-rc6
jz-2.6.34-rc7
jz-2.6.35
jz-2.6.36
jz-2.6.37
jz-2.6.38
jz-2.6.39
jz-3.0
jz-3.1
jz-3.11
jz-3.12
jz-3.13
jz-3.15
jz-3.16
jz-3.18-dt
jz-3.2
jz-3.3
jz-3.4
jz-3.5
jz-3.6
jz-3.6-rc2-pwm
jz-3.9
jz-3.9-clk
jz-3.9-rc8
jz47xx
jz47xx-2.6.38
master
Tags:
od-2011-09-04
od-2011-09-18
v2.6.34-rc5
v2.6.34-rc6
v2.6.34-rc7
v3.9