2 * Marvell EBU clock core handling defined at reset
4 * Copyright (C) 2012 Marvell
6 * Gregory CLEMENT <gregory.clement@free-electrons.com>
7 * Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
9 * This file is licensed under the terms of the GNU General Public
10 * License version 2. This program is licensed "as is" without any
11 * warranty of any kind, whether express or implied.
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>
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;
35 static struct clk_onecell_data clk_data;
37 static void __init mvebu_clk_core_setup(struct device_node *np,
38 struct core_clocks *coreclk)
40 const char *tclk_name = "tclk";
41 const char *cpuclk_name = "cpuclk";
46 base = of_iomap(np, 0);
51 * Allocate struct for TCLK, cpu clk, and core ratio clocks
53 clk_data.clk_num = 2 + coreclk->num_ratios;
54 clk_data.clks = kzalloc(clk_data.clk_num * sizeof(struct clk *),
56 if (WARN_ON(!clk_data.clks))
62 of_property_read_string_index(np, "clock-output-names", 0,
64 rate = coreclk->get_tclk_freq(base);
65 clk_data.clks[0] = clk_register_fixed_rate(NULL, tclk_name, NULL,
67 WARN_ON(IS_ERR(clk_data.clks[0]));
72 of_property_read_string_index(np, "clock-output-names", 1,
74 rate = coreclk->get_cpu_freq(base);
75 clk_data.clks[1] = clk_register_fixed_rate(NULL, cpuclk_name, NULL,
77 WARN_ON(IS_ERR(clk_data.clks[1]));
80 * Register fixed-factor clocks derived from CPU clock
82 for (n = 0; n < coreclk->num_ratios; n++) {
83 const char *rclk_name = coreclk->ratios[n].name;
86 of_property_read_string_index(np, "clock-output-names",
88 coreclk->get_clk_ratio(base, coreclk->ratios[n].id,
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]));
96 * SAR register isn't needed anymore
100 of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data);
103 #ifdef CONFIG_MACH_ARMADA_370_XP
105 * Armada 370/XP Sample At Reset is a 64 bit bitfiled split in two
106 * register of 32 bits
109 #define SARL 0 /* Low part [0:31] */
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 /* High part [32:63] */
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
128 static const u32 __initconst armada_370_tclk_frequencies[] = {
133 static u32 __init armada_370_get_tclk_freq(void __iomem *sar)
135 u8 tclk_freq_select = 0;
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];
142 static const u32 __initconst armada_370_cpu_frequencies[] = {
152 static u32 __init armada_370_get_cpu_freq(void __iomem *sar)
155 u8 cpu_freq_select = 0;
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 unsuported %d\n", cpu_freq_select);
163 cpu_freq = armada_370_cpu_frequencies[cpu_freq_select];
168 enum { A370_XP_NBCLK, A370_XP_HCLK, A370_XP_DRAMCLK };
170 static 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" },
176 static 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},
187 static 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},
198 static 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},
209 static void __init armada_370_xp_get_clk_ratio(u32 opt,
210 void __iomem *sar, int id, int *mult, int *div)
214 *mult = armada_370_xp_nbclk_ratios[opt][0];
215 *div = armada_370_xp_nbclk_ratios[opt][1];
218 *mult = armada_370_xp_hclk_ratios[opt][0];
219 *div = armada_370_xp_hclk_ratios[opt][1];
221 case A370_XP_DRAMCLK:
222 *mult = armada_370_xp_dramclk_ratios[opt][0];
223 *div = armada_370_xp_dramclk_ratios[opt][1];
228 static void __init armada_370_get_clk_ratio(
229 void __iomem *sar, int id, int *mult, int *div)
231 u32 opt = ((readl(sar) >> SARL_A370_FAB_FREQ_OPT) &
232 SARL_A370_FAB_FREQ_OPT_MASK);
234 armada_370_xp_get_clk_ratio(opt, sar, id, mult, div);
238 static 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),
246 static const u32 __initconst armada_xp_cpu_frequencies[] = {
261 /* For Armada XP TCLK frequency is fix: 250MHz */
262 static u32 __init armada_xp_get_tclk_freq(void __iomem *sar)
264 return 250 * 1000 * 1000;
267 static u32 __init armada_xp_get_cpu_freq(void __iomem *sar)
270 u8 cpu_freq_select = 0;
272 cpu_freq_select = ((readl(sar) >> SARL_AXP_PCLK_FREQ_OPT) &
273 SARL_AXP_PCLK_FREQ_OPT_MASK);
275 * The upper bit is not contiguous to the other ones and
276 * located in the high part of the SAR registers
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 unsuported: %d\n", cpu_freq_select);
285 cpu_freq = armada_xp_cpu_frequencies[cpu_freq_select];
290 static void __init armada_xp_get_clk_ratio(
291 void __iomem *sar, int id, int *mult, int *div)
294 u32 opt = ((readl(sar) >> SARL_AXP_FAB_FREQ_OPT) &
295 SARL_AXP_FAB_FREQ_OPT_MASK);
297 * The upper bit is not contiguous to the other ones and
298 * located in the high part of the SAR registers
300 opt |= (((readl(sar+4) >> SARH_AXP_FAB_FREQ_OPT) &
301 SARH_AXP_FAB_FREQ_OPT_MASK)
302 << SARH_AXP_FAB_FREQ_OPT_SHIFT);
304 armada_370_xp_get_clk_ratio(opt, sar, id, mult, div);
307 static 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),
315 #endif /* CONFIG_MACH_ARMADA_370_XP */
318 * Dove PLL sample-at-reset configuration
320 * SAR0[8:5] : CPU frequency
334 * SAR0[11:9] : CPU to L2 Clock divider ratio
341 * SAR0[15:12] : CPU to DDR DRAM Clock divider ratio
354 * SAR0[24:23] : TCLK frequency
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
369 static const u32 __initconst dove_tclk_frequencies[] = {
375 static u32 __init dove_get_tclk_freq(void __iomem *sar)
377 u32 opt = (readl(sar) >> SAR_DOVE_TCLK_FREQ) &
378 SAR_DOVE_TCLK_FREQ_MASK;
379 return dove_tclk_frequencies[opt];
382 static const u32 __initconst dove_cpu_frequencies[] = {
385 933333333, 933333333,
386 800000000, 800000000, 800000000,
394 static u32 __init dove_get_cpu_freq(void __iomem *sar)
396 u32 opt = (readl(sar) >> SAR_DOVE_CPU_FREQ) &
397 SAR_DOVE_CPU_FREQ_MASK;
398 return dove_cpu_frequencies[opt];
401 enum { DOVE_CPU_TO_L2, DOVE_CPU_TO_DDR };
403 static const struct core_ratio __initconst dove_core_ratios[] = {
404 { .id = DOVE_CPU_TO_L2, .name = "l2clk", },
405 { .id = DOVE_CPU_TO_DDR, .name = "ddrclk", }
408 static 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 }
413 static 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 }
420 static void __init dove_get_clk_ratio(
421 void __iomem *sar, int id, int *mult, int *div)
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];
432 case DOVE_CPU_TO_DDR:
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];
443 static 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),
450 #endif /* CONFIG_ARCH_DOVE */
453 * Kirkwood PLL sample-at-reset configuration
454 * (6180 has different SAR layout than other Kirkwood SoCs)
456 * SAR0[4:3,22,1] : CPU frequency (6281,6292,6282)
467 * SAR0[19,10:9] : CPU to L2 Clock divider ratio (6281,6292,6282)
473 * SAR0[8:5] : CPU to DDR DRAM Clock divider ratio (6281,6292,6282)
482 * SAR0[4:2] : Kirkwood 6180 cpu/l2/ddr clock configuration (6180 only)
483 * 5 = [CPU = 600 MHz, L2 = (1/2) * CPU, DDR = 200 MHz = (1/3) * CPU]
484 * 6 = [CPU = 800 MHz, L2 = (1/2) * CPU, DDR = 200 MHz = (1/4) * CPU]
485 * 7 = [CPU = 1000 MHz, L2 = (1/2) * CPU, DDR = 200 MHz = (1/5) * CPU]
488 * SAR0[21] : TCLK frequency
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
508 enum { KIRKWOOD_CPU_TO_L2, KIRKWOOD_CPU_TO_DDR };
510 static const struct core_ratio __initconst kirkwood_core_ratios[] = {
511 { .id = KIRKWOOD_CPU_TO_L2, .name = "l2clk", },
512 { .id = KIRKWOOD_CPU_TO_DDR, .name = "ddrclk", }
515 static u32 __init kirkwood_get_tclk_freq(void __iomem *sar)
517 u32 opt = (readl(sar) >> SAR_KIRKWOOD_TCLK_FREQ) &
518 SAR_KIRKWOOD_TCLK_FREQ_MASK;
519 return (opt) ? 166666667 : 200000000;
522 static const u32 __initconst kirkwood_cpu_frequencies[] = {
537 static u32 __init kirkwood_get_cpu_freq(void __iomem *sar)
539 u32 opt = SAR_KIRKWOOD_CPU_FREQ(readl(sar));
540 return kirkwood_cpu_frequencies[opt];
543 static 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 }
548 static 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 }
555 static void __init kirkwood_get_clk_ratio(
556 void __iomem *sar, int id, int *mult, int *div)
559 case KIRKWOOD_CPU_TO_L2:
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];
566 case KIRKWOOD_CPU_TO_DDR:
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];
577 static 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),
585 static const u32 __initconst mv88f6180_cpu_frequencies[] = {
592 static u32 __init mv88f6180_get_cpu_freq(void __iomem *sar)
594 u32 opt = (readl(sar) >> SAR_MV88F6180_CLK) & SAR_MV88F6180_CLK_MASK;
595 return mv88f6180_cpu_frequencies[opt];
598 static 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 }
603 static void __init mv88f6180_get_clk_ratio(
604 void __iomem *sar, int id, int *mult, int *div)
607 case KIRKWOOD_CPU_TO_L2:
609 /* mv88f6180 has a fixed 1:2 CPU-to-L2 ratio */
614 case KIRKWOOD_CPU_TO_DDR:
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];
625 static 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),
632 #endif /* CONFIG_ARCH_KIRKWOOD */
634 static const __initdata struct of_device_id clk_core_match[] = {
635 #ifdef CONFIG_MACH_ARMADA_370_XP
637 .compatible = "marvell,armada-370-core-clock",
638 .data = &armada_370_core_clocks,
641 .compatible = "marvell,armada-xp-core-clock",
642 .data = &armada_xp_core_clocks,
645 #ifdef CONFIG_ARCH_DOVE
647 .compatible = "marvell,dove-core-clock",
648 .data = &dove_core_clocks,
652 #ifdef CONFIG_ARCH_KIRKWOOD
654 .compatible = "marvell,kirkwood-core-clock",
655 .data = &kirkwood_core_clocks,
658 .compatible = "marvell,mv88f6180-core-clock",
659 .data = &mv88f6180_core_clocks,
666 void __init mvebu_core_clk_init(void)
668 struct device_node *np;
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);