1
2
3
4
5
6
7
8
9
10
11
12
13#include <linux/kernel.h>
14#include <linux/clk.h>
15#include <linux/clkdev.h>
16#include <linux/clk-provider.h>
17#include <linux/of_address.h>
18#include <linux/io.h>
19#include <linux/of.h>
20#include "clk-core.h"
21
22struct core_ratio {
23 int id;
24 const char *name;
25};
26
27struct core_clocks {
28 u32 (*get_tclk_freq)(void __iomem *sar);
29 u32 (*get_cpu_freq)(void __iomem *sar);
30 void (*get_clk_ratio)(void __iomem *sar, int id, int *mult, int *div);
31 const struct core_ratio *ratios;
32 int num_ratios;
33};
34
35static struct clk_onecell_data clk_data;
36
37static void __init mvebu_clk_core_setup(struct device_node *np,
38 struct core_clocks *coreclk)
39{
40 const char *tclk_name = "tclk";
41 const char *cpuclk_name = "cpuclk";
42 void __iomem *base;
43 unsigned long rate;
44 int n;
45
46 base = of_iomap(np, 0);
47 if (WARN_ON(!base))
48 return;
49
50
51
52
53 clk_data.clk_num = 2 + coreclk->num_ratios;
54 clk_data.clks = kzalloc(clk_data.clk_num * sizeof(struct clk *),
55 GFP_KERNEL);
56 if (WARN_ON(!clk_data.clks))
57 return;
58
59
60
61
62 of_property_read_string_index(np, "clock-output-names", 0,
63 &tclk_name);
64 rate = coreclk->get_tclk_freq(base);
65 clk_data.clks[0] = clk_register_fixed_rate(NULL, tclk_name, NULL,
66 CLK_IS_ROOT, rate);
67 WARN_ON(IS_ERR(clk_data.clks[0]));
68
69
70
71
72 of_property_read_string_index(np, "clock-output-names", 1,
73 &cpuclk_name);
74 rate = coreclk->get_cpu_freq(base);
75 clk_data.clks[1] = clk_register_fixed_rate(NULL, cpuclk_name, NULL,
76 CLK_IS_ROOT, rate);
77 WARN_ON(IS_ERR(clk_data.clks[1]));
78
79
80
81
82 for (n = 0; n < coreclk->num_ratios; n++) {
83 const char *rclk_name = coreclk->ratios[n].name;
84 int mult, div;
85
86 of_property_read_string_index(np, "clock-output-names",
87 2+n, &rclk_name);
88 coreclk->get_clk_ratio(base, coreclk->ratios[n].id,
89 &mult, &div);
90 clk_data.clks[2+n] = clk_register_fixed_factor(NULL, rclk_name,
91 cpuclk_name, 0, mult, div);
92 WARN_ON(IS_ERR(clk_data.clks[2+n]));
93 };
94
95
96
97
98 iounmap(base);
99
100 of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data);
101}
102
103#ifdef CONFIG_MACH_ARMADA_370_XP
104
105
106
107
108
109#define SARL 0
110#define SARL_AXP_PCLK_FREQ_OPT 21
111#define SARL_AXP_PCLK_FREQ_OPT_MASK 0x7
112#define SARL_A370_PCLK_FREQ_OPT 11
113#define SARL_A370_PCLK_FREQ_OPT_MASK 0xF
114#define SARL_AXP_FAB_FREQ_OPT 24
115#define SARL_AXP_FAB_FREQ_OPT_MASK 0xF
116#define SARL_A370_FAB_FREQ_OPT 15
117#define SARL_A370_FAB_FREQ_OPT_MASK 0x1F
118#define SARL_A370_TCLK_FREQ_OPT 20
119#define SARL_A370_TCLK_FREQ_OPT_MASK 0x1
120#define SARH 4
121#define SARH_AXP_PCLK_FREQ_OPT (52-32)
122#define SARH_AXP_PCLK_FREQ_OPT_MASK 0x1
123#define SARH_AXP_PCLK_FREQ_OPT_SHIFT 3
124#define SARH_AXP_FAB_FREQ_OPT (51-32)
125#define SARH_AXP_FAB_FREQ_OPT_MASK 0x1
126#define SARH_AXP_FAB_FREQ_OPT_SHIFT 4
127
128static const u32 __initconst armada_370_tclk_frequencies[] = {
129 166000000,
130 200000000,
131};
132
133static u32 __init armada_370_get_tclk_freq(void __iomem *sar)
134{
135 u8 tclk_freq_select = 0;
136
137 tclk_freq_select = ((readl(sar) >> SARL_A370_TCLK_FREQ_OPT) &
138 SARL_A370_TCLK_FREQ_OPT_MASK);
139 return armada_370_tclk_frequencies[tclk_freq_select];
140}
141
142static const u32 __initconst armada_370_cpu_frequencies[] = {
143 400000000,
144 533000000,
145 667000000,
146 800000000,
147 1000000000,
148 1067000000,
149 1200000000,
150};
151
152static u32 __init armada_370_get_cpu_freq(void __iomem *sar)
153{
154 u32 cpu_freq;
155 u8 cpu_freq_select = 0;
156
157 cpu_freq_select = ((readl(sar) >> SARL_A370_PCLK_FREQ_OPT) &
158 SARL_A370_PCLK_FREQ_OPT_MASK);
159 if (cpu_freq_select >= ARRAY_SIZE(armada_370_cpu_frequencies)) {
160 pr_err("CPU freq select unsupported %d\n", cpu_freq_select);
161 cpu_freq = 0;
162 } else
163 cpu_freq = armada_370_cpu_frequencies[cpu_freq_select];
164
165 return cpu_freq;
166}
167
168enum { A370_XP_NBCLK, A370_XP_HCLK, A370_XP_DRAMCLK };
169
170static const struct core_ratio __initconst armada_370_xp_core_ratios[] = {
171 { .id = A370_XP_NBCLK, .name = "nbclk" },
172 { .id = A370_XP_HCLK, .name = "hclk" },
173 { .id = A370_XP_DRAMCLK, .name = "dramclk" },
174};
175
176static const int __initconst armada_370_xp_nbclk_ratios[32][2] = {
177 {0, 1}, {1, 2}, {2, 2}, {2, 2},
178 {1, 2}, {1, 2}, {1, 1}, {2, 3},
179 {0, 1}, {1, 2}, {2, 4}, {0, 1},
180 {1, 2}, {0, 1}, {0, 1}, {2, 2},
181 {0, 1}, {0, 1}, {0, 1}, {1, 1},
182 {2, 3}, {0, 1}, {0, 1}, {0, 1},
183 {0, 1}, {0, 1}, {0, 1}, {1, 1},
184 {0, 1}, {0, 1}, {0, 1}, {0, 1},
185};
186
187static const int __initconst armada_370_xp_hclk_ratios[32][2] = {
188 {0, 1}, {1, 2}, {2, 6}, {2, 3},
189 {1, 3}, {1, 4}, {1, 2}, {2, 6},
190 {0, 1}, {1, 6}, {2, 10}, {0, 1},
191 {1, 4}, {0, 1}, {0, 1}, {2, 5},
192 {0, 1}, {0, 1}, {0, 1}, {1, 2},
193 {2, 6}, {0, 1}, {0, 1}, {0, 1},
194 {0, 1}, {0, 1}, {0, 1}, {1, 1},
195 {0, 1}, {0, 1}, {0, 1}, {0, 1},
196};
197
198static const int __initconst armada_370_xp_dramclk_ratios[32][2] = {
199 {0, 1}, {1, 2}, {2, 3}, {2, 3},
200 {1, 3}, {1, 2}, {1, 2}, {2, 6},
201 {0, 1}, {1, 3}, {2, 5}, {0, 1},
202 {1, 4}, {0, 1}, {0, 1}, {2, 5},
203 {0, 1}, {0, 1}, {0, 1}, {1, 1},
204 {2, 3}, {0, 1}, {0, 1}, {0, 1},
205 {0, 1}, {0, 1}, {0, 1}, {1, 1},
206 {0, 1}, {0, 1}, {0, 1}, {0, 1},
207};
208
209static void __init armada_370_xp_get_clk_ratio(u32 opt,
210 void __iomem *sar, int id, int *mult, int *div)
211{
212 switch (id) {
213 case A370_XP_NBCLK:
214 *mult = armada_370_xp_nbclk_ratios[opt][0];
215 *div = armada_370_xp_nbclk_ratios[opt][1];
216 break;
217 case A370_XP_HCLK:
218 *mult = armada_370_xp_hclk_ratios[opt][0];
219 *div = armada_370_xp_hclk_ratios[opt][1];
220 break;
221 case A370_XP_DRAMCLK:
222 *mult = armada_370_xp_dramclk_ratios[opt][0];
223 *div = armada_370_xp_dramclk_ratios[opt][1];
224 break;
225 }
226}
227
228static void __init armada_370_get_clk_ratio(
229 void __iomem *sar, int id, int *mult, int *div)
230{
231 u32 opt = ((readl(sar) >> SARL_A370_FAB_FREQ_OPT) &
232 SARL_A370_FAB_FREQ_OPT_MASK);
233
234 armada_370_xp_get_clk_ratio(opt, sar, id, mult, div);
235}
236
237
238static const struct core_clocks armada_370_core_clocks = {
239 .get_tclk_freq = armada_370_get_tclk_freq,
240 .get_cpu_freq = armada_370_get_cpu_freq,
241 .get_clk_ratio = armada_370_get_clk_ratio,
242 .ratios = armada_370_xp_core_ratios,
243 .num_ratios = ARRAY_SIZE(armada_370_xp_core_ratios),
244};
245
246static const u32 __initconst armada_xp_cpu_frequencies[] = {
247 1000000000,
248 1066000000,
249 1200000000,
250 1333000000,
251 1500000000,
252 1666000000,
253 1800000000,
254 2000000000,
255 667000000,
256 0,
257 800000000,
258 1600000000,
259};
260
261
262static u32 __init armada_xp_get_tclk_freq(void __iomem *sar)
263{
264 return 250 * 1000 * 1000;
265}
266
267static u32 __init armada_xp_get_cpu_freq(void __iomem *sar)
268{
269 u32 cpu_freq;
270 u8 cpu_freq_select = 0;
271
272 cpu_freq_select = ((readl(sar) >> SARL_AXP_PCLK_FREQ_OPT) &
273 SARL_AXP_PCLK_FREQ_OPT_MASK);
274
275
276
277
278 cpu_freq_select |= (((readl(sar+4) >> SARH_AXP_PCLK_FREQ_OPT) &
279 SARH_AXP_PCLK_FREQ_OPT_MASK)
280 << SARH_AXP_PCLK_FREQ_OPT_SHIFT);
281 if (cpu_freq_select >= ARRAY_SIZE(armada_xp_cpu_frequencies)) {
282 pr_err("CPU freq select unsupported: %d\n", cpu_freq_select);
283 cpu_freq = 0;
284 } else
285 cpu_freq = armada_xp_cpu_frequencies[cpu_freq_select];
286
287 return cpu_freq;
288}
289
290static void __init armada_xp_get_clk_ratio(
291 void __iomem *sar, int id, int *mult, int *div)
292{
293
294 u32 opt = ((readl(sar) >> SARL_AXP_FAB_FREQ_OPT) &
295 SARL_AXP_FAB_FREQ_OPT_MASK);
296
297
298
299
300 opt |= (((readl(sar+4) >> SARH_AXP_FAB_FREQ_OPT) &
301 SARH_AXP_FAB_FREQ_OPT_MASK)
302 << SARH_AXP_FAB_FREQ_OPT_SHIFT);
303
304 armada_370_xp_get_clk_ratio(opt, sar, id, mult, div);
305}
306
307static const struct core_clocks armada_xp_core_clocks = {
308 .get_tclk_freq = armada_xp_get_tclk_freq,
309 .get_cpu_freq = armada_xp_get_cpu_freq,
310 .get_clk_ratio = armada_xp_get_clk_ratio,
311 .ratios = armada_370_xp_core_ratios,
312 .num_ratios = ARRAY_SIZE(armada_370_xp_core_ratios),
313};
314
315#endif
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359#ifdef CONFIG_ARCH_DOVE
360#define SAR_DOVE_CPU_FREQ 5
361#define SAR_DOVE_CPU_FREQ_MASK 0xf
362#define SAR_DOVE_L2_RATIO 9
363#define SAR_DOVE_L2_RATIO_MASK 0x7
364#define SAR_DOVE_DDR_RATIO 12
365#define SAR_DOVE_DDR_RATIO_MASK 0xf
366#define SAR_DOVE_TCLK_FREQ 23
367#define SAR_DOVE_TCLK_FREQ_MASK 0x3
368
369static const u32 __initconst dove_tclk_frequencies[] = {
370 166666667,
371 125000000,
372 0, 0
373};
374
375static u32 __init dove_get_tclk_freq(void __iomem *sar)
376{
377 u32 opt = (readl(sar) >> SAR_DOVE_TCLK_FREQ) &
378 SAR_DOVE_TCLK_FREQ_MASK;
379 return dove_tclk_frequencies[opt];
380}
381
382static const u32 __initconst dove_cpu_frequencies[] = {
383 0, 0, 0, 0, 0,
384 1000000000,
385 933333333, 933333333,
386 800000000, 800000000, 800000000,
387 1066666667,
388 666666667,
389 533333333,
390 400000000,
391 333333333
392};
393
394static u32 __init dove_get_cpu_freq(void __iomem *sar)
395{
396 u32 opt = (readl(sar) >> SAR_DOVE_CPU_FREQ) &
397 SAR_DOVE_CPU_FREQ_MASK;
398 return dove_cpu_frequencies[opt];
399}
400
401enum { DOVE_CPU_TO_L2, DOVE_CPU_TO_DDR };
402
403static const struct core_ratio __initconst dove_core_ratios[] = {
404 { .id = DOVE_CPU_TO_L2, .name = "l2clk", },
405 { .id = DOVE_CPU_TO_DDR, .name = "ddrclk", }
406};
407
408static const int __initconst dove_cpu_l2_ratios[8][2] = {
409 { 1, 1 }, { 0, 1 }, { 1, 2 }, { 0, 1 },
410 { 1, 3 }, { 0, 1 }, { 1, 4 }, { 0, 1 }
411};
412
413static const int __initconst dove_cpu_ddr_ratios[16][2] = {
414 { 1, 1 }, { 0, 1 }, { 1, 2 }, { 2, 5 },
415 { 1, 3 }, { 0, 1 }, { 1, 4 }, { 0, 1 },
416 { 1, 5 }, { 0, 1 }, { 1, 6 }, { 0, 1 },
417 { 1, 7 }, { 0, 1 }, { 1, 8 }, { 1, 10 }
418};
419
420static void __init dove_get_clk_ratio(
421 void __iomem *sar, int id, int *mult, int *div)
422{
423 switch (id) {
424 case DOVE_CPU_TO_L2:
425 {
426 u32 opt = (readl(sar) >> SAR_DOVE_L2_RATIO) &
427 SAR_DOVE_L2_RATIO_MASK;
428 *mult = dove_cpu_l2_ratios[opt][0];
429 *div = dove_cpu_l2_ratios[opt][1];
430 break;
431 }
432 case DOVE_CPU_TO_DDR:
433 {
434 u32 opt = (readl(sar) >> SAR_DOVE_DDR_RATIO) &
435 SAR_DOVE_DDR_RATIO_MASK;
436 *mult = dove_cpu_ddr_ratios[opt][0];
437 *div = dove_cpu_ddr_ratios[opt][1];
438 break;
439 }
440 }
441}
442
443static const struct core_clocks dove_core_clocks = {
444 .get_tclk_freq = dove_get_tclk_freq,
445 .get_cpu_freq = dove_get_cpu_freq,
446 .get_clk_ratio = dove_get_clk_ratio,
447 .ratios = dove_core_ratios,
448 .num_ratios = ARRAY_SIZE(dove_core_ratios),
449};
450#endif
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493#ifdef CONFIG_ARCH_KIRKWOOD
494#define SAR_KIRKWOOD_CPU_FREQ(x) \
495 (((x & (1 << 1)) >> 1) | \
496 ((x & (1 << 22)) >> 21) | \
497 ((x & (3 << 3)) >> 1))
498#define SAR_KIRKWOOD_L2_RATIO(x) \
499 (((x & (3 << 9)) >> 9) | \
500 (((x & (1 << 19)) >> 17)))
501#define SAR_KIRKWOOD_DDR_RATIO 5
502#define SAR_KIRKWOOD_DDR_RATIO_MASK 0xf
503#define SAR_MV88F6180_CLK 2
504#define SAR_MV88F6180_CLK_MASK 0x7
505#define SAR_KIRKWOOD_TCLK_FREQ 21
506#define SAR_KIRKWOOD_TCLK_FREQ_MASK 0x1
507
508enum { KIRKWOOD_CPU_TO_L2, KIRKWOOD_CPU_TO_DDR };
509
510static const struct core_ratio __initconst kirkwood_core_ratios[] = {
511 { .id = KIRKWOOD_CPU_TO_L2, .name = "l2clk", },
512 { .id = KIRKWOOD_CPU_TO_DDR, .name = "ddrclk", }
513};
514
515static u32 __init kirkwood_get_tclk_freq(void __iomem *sar)
516{
517 u32 opt = (readl(sar) >> SAR_KIRKWOOD_TCLK_FREQ) &
518 SAR_KIRKWOOD_TCLK_FREQ_MASK;
519 return (opt) ? 166666667 : 200000000;
520}
521
522static const u32 __initconst kirkwood_cpu_frequencies[] = {
523 0, 0, 0, 0,
524 600000000,
525 0,
526 800000000,
527 1000000000,
528 0,
529 1200000000,
530 0, 0,
531 1500000000,
532 1600000000,
533 1800000000,
534 2000000000
535};
536
537static u32 __init kirkwood_get_cpu_freq(void __iomem *sar)
538{
539 u32 opt = SAR_KIRKWOOD_CPU_FREQ(readl(sar));
540 return kirkwood_cpu_frequencies[opt];
541}
542
543static const int __initconst kirkwood_cpu_l2_ratios[8][2] = {
544 { 0, 1 }, { 1, 2 }, { 0, 1 }, { 1, 3 },
545 { 0, 1 }, { 1, 4 }, { 0, 1 }, { 0, 1 }
546};
547
548static const int __initconst kirkwood_cpu_ddr_ratios[16][2] = {
549 { 0, 1 }, { 0, 1 }, { 1, 2 }, { 0, 1 },
550 { 1, 3 }, { 0, 1 }, { 1, 4 }, { 2, 9 },
551 { 1, 5 }, { 1, 6 }, { 0, 1 }, { 0, 1 },
552 { 0, 1 }, { 0, 1 }, { 0, 1 }, { 0, 1 }
553};
554
555static void __init kirkwood_get_clk_ratio(
556 void __iomem *sar, int id, int *mult, int *div)
557{
558 switch (id) {
559 case KIRKWOOD_CPU_TO_L2:
560 {
561 u32 opt = SAR_KIRKWOOD_L2_RATIO(readl(sar));
562 *mult = kirkwood_cpu_l2_ratios[opt][0];
563 *div = kirkwood_cpu_l2_ratios[opt][1];
564 break;
565 }
566 case KIRKWOOD_CPU_TO_DDR:
567 {
568 u32 opt = (readl(sar) >> SAR_KIRKWOOD_DDR_RATIO) &
569 SAR_KIRKWOOD_DDR_RATIO_MASK;
570 *mult = kirkwood_cpu_ddr_ratios[opt][0];
571 *div = kirkwood_cpu_ddr_ratios[opt][1];
572 break;
573 }
574 }
575}
576
577static const struct core_clocks kirkwood_core_clocks = {
578 .get_tclk_freq = kirkwood_get_tclk_freq,
579 .get_cpu_freq = kirkwood_get_cpu_freq,
580 .get_clk_ratio = kirkwood_get_clk_ratio,
581 .ratios = kirkwood_core_ratios,
582 .num_ratios = ARRAY_SIZE(kirkwood_core_ratios),
583};
584
585static const u32 __initconst mv88f6180_cpu_frequencies[] = {
586 0, 0, 0, 0, 0,
587 600000000,
588 800000000,
589 1000000000
590};
591
592static u32 __init mv88f6180_get_cpu_freq(void __iomem *sar)
593{
594 u32 opt = (readl(sar) >> SAR_MV88F6180_CLK) & SAR_MV88F6180_CLK_MASK;
595 return mv88f6180_cpu_frequencies[opt];
596}
597
598static const int __initconst mv88f6180_cpu_ddr_ratios[8][2] = {
599 { 0, 1 }, { 0, 1 }, { 0, 1 }, { 0, 1 },
600 { 0, 1 }, { 1, 3 }, { 1, 4 }, { 1, 5 }
601};
602
603static void __init mv88f6180_get_clk_ratio(
604 void __iomem *sar, int id, int *mult, int *div)
605{
606 switch (id) {
607 case KIRKWOOD_CPU_TO_L2:
608 {
609
610 *mult = 1;
611 *div = 2;
612 break;
613 }
614 case KIRKWOOD_CPU_TO_DDR:
615 {
616 u32 opt = (readl(sar) >> SAR_MV88F6180_CLK) &
617 SAR_MV88F6180_CLK_MASK;
618 *mult = mv88f6180_cpu_ddr_ratios[opt][0];
619 *div = mv88f6180_cpu_ddr_ratios[opt][1];
620 break;
621 }
622 }
623}
624
625static const struct core_clocks mv88f6180_core_clocks = {
626 .get_tclk_freq = kirkwood_get_tclk_freq,
627 .get_cpu_freq = mv88f6180_get_cpu_freq,
628 .get_clk_ratio = mv88f6180_get_clk_ratio,
629 .ratios = kirkwood_core_ratios,
630 .num_ratios = ARRAY_SIZE(kirkwood_core_ratios),
631};
632#endif
633
634static const __initdata struct of_device_id clk_core_match[] = {
635#ifdef CONFIG_MACH_ARMADA_370_XP
636 {
637 .compatible = "marvell,armada-370-core-clock",
638 .data = &armada_370_core_clocks,
639 },
640 {
641 .compatible = "marvell,armada-xp-core-clock",
642 .data = &armada_xp_core_clocks,
643 },
644#endif
645#ifdef CONFIG_ARCH_DOVE
646 {
647 .compatible = "marvell,dove-core-clock",
648 .data = &dove_core_clocks,
649 },
650#endif
651
652#ifdef CONFIG_ARCH_KIRKWOOD
653 {
654 .compatible = "marvell,kirkwood-core-clock",
655 .data = &kirkwood_core_clocks,
656 },
657 {
658 .compatible = "marvell,mv88f6180-core-clock",
659 .data = &mv88f6180_core_clocks,
660 },
661#endif
662
663 { }
664};
665
666void __init mvebu_core_clk_init(void)
667{
668 struct device_node *np;
669
670 for_each_matching_node(np, clk_core_match) {
671 const struct of_device_id *match =
672 of_match_node(clk_core_match, np);
673 mvebu_clk_core_setup(np, (struct core_clocks *)match->data);
674 }
675}
676