diff options
Diffstat (limited to 'drivers/clk/mvebu/armada-38x.c')
-rw-r--r-- | drivers/clk/mvebu/armada-38x.c | 167 |
1 files changed, 167 insertions, 0 deletions
diff --git a/drivers/clk/mvebu/armada-38x.c b/drivers/clk/mvebu/armada-38x.c new file mode 100644 index 000000000000..8bccf4ecdab6 --- /dev/null +++ b/drivers/clk/mvebu/armada-38x.c | |||
@@ -0,0 +1,167 @@ | |||
1 | /* | ||
2 | * Marvell Armada 380/385 SoC clocks | ||
3 | * | ||
4 | * Copyright (C) 2014 Marvell | ||
5 | * | ||
6 | * Gregory CLEMENT <gregory.clement@free-electrons.com> | ||
7 | * Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com> | ||
8 | * Andrew Lunn <andrew@lunn.ch> | ||
9 | * | ||
10 | * This file is licensed under the terms of the GNU General Public | ||
11 | * License version 2. This program is licensed "as is" without any | ||
12 | * warranty of any kind, whether express or implied. | ||
13 | */ | ||
14 | |||
15 | #include <linux/kernel.h> | ||
16 | #include <linux/clk-provider.h> | ||
17 | #include <linux/io.h> | ||
18 | #include <linux/of.h> | ||
19 | #include "common.h" | ||
20 | |||
21 | /* | ||
22 | * SAR[14:10] : Ratios between PCLK0, NBCLK, HCLK and DRAM clocks | ||
23 | * | ||
24 | * SAR[15] : TCLK frequency | ||
25 | * 0 = 250 MHz | ||
26 | * 1 = 200 MHz | ||
27 | */ | ||
28 | |||
29 | #define SAR_A380_TCLK_FREQ_OPT 15 | ||
30 | #define SAR_A380_TCLK_FREQ_OPT_MASK 0x1 | ||
31 | #define SAR_A380_CPU_DDR_L2_FREQ_OPT 10 | ||
32 | #define SAR_A380_CPU_DDR_L2_FREQ_OPT_MASK 0x1F | ||
33 | |||
34 | static const u32 armada_38x_tclk_frequencies[] __initconst = { | ||
35 | 250000000, | ||
36 | 200000000, | ||
37 | }; | ||
38 | |||
39 | static u32 __init armada_38x_get_tclk_freq(void __iomem *sar) | ||
40 | { | ||
41 | u8 tclk_freq_select; | ||
42 | |||
43 | tclk_freq_select = ((readl(sar) >> SAR_A380_TCLK_FREQ_OPT) & | ||
44 | SAR_A380_TCLK_FREQ_OPT_MASK); | ||
45 | return armada_38x_tclk_frequencies[tclk_freq_select]; | ||
46 | } | ||
47 | |||
48 | static const u32 armada_38x_cpu_frequencies[] __initconst = { | ||
49 | 0, 0, 0, 0, | ||
50 | 1066 * 1000 * 1000, 0, 0, 0, | ||
51 | 1332 * 1000 * 1000, 0, 0, 0, | ||
52 | 1600 * 1000 * 1000, | ||
53 | }; | ||
54 | |||
55 | static u32 __init armada_38x_get_cpu_freq(void __iomem *sar) | ||
56 | { | ||
57 | u8 cpu_freq_select; | ||
58 | |||
59 | cpu_freq_select = ((readl(sar) >> SAR_A380_CPU_DDR_L2_FREQ_OPT) & | ||
60 | SAR_A380_CPU_DDR_L2_FREQ_OPT_MASK); | ||
61 | if (cpu_freq_select >= ARRAY_SIZE(armada_38x_cpu_frequencies)) { | ||
62 | pr_err("Selected CPU frequency (%d) unsupported\n", | ||
63 | cpu_freq_select); | ||
64 | return 0; | ||
65 | } | ||
66 | |||
67 | return armada_38x_cpu_frequencies[cpu_freq_select]; | ||
68 | } | ||
69 | |||
70 | enum { A380_CPU_TO_DDR, A380_CPU_TO_L2 }; | ||
71 | |||
72 | static const struct coreclk_ratio armada_38x_coreclk_ratios[] __initconst = { | ||
73 | { .id = A380_CPU_TO_L2, .name = "l2clk" }, | ||
74 | { .id = A380_CPU_TO_DDR, .name = "ddrclk" }, | ||
75 | }; | ||
76 | |||
77 | static const int armada_38x_cpu_l2_ratios[32][2] __initconst = { | ||
78 | {0, 1}, {0, 1}, {0, 1}, {0, 1}, | ||
79 | {1, 2}, {0, 1}, {0, 1}, {0, 1}, | ||
80 | {1, 2}, {0, 1}, {0, 1}, {0, 1}, | ||
81 | {1, 2}, {0, 1}, {0, 1}, {0, 1}, | ||
82 | {0, 1}, {0, 1}, {0, 1}, {0, 1}, | ||
83 | {0, 1}, {0, 1}, {0, 1}, {0, 1}, | ||
84 | {0, 1}, {0, 1}, {0, 1}, {0, 1}, | ||
85 | {0, 1}, {0, 1}, {0, 1}, {0, 1}, | ||
86 | }; | ||
87 | |||
88 | static const int armada_38x_cpu_ddr_ratios[32][2] __initconst = { | ||
89 | {0, 1}, {0, 1}, {0, 1}, {0, 1}, | ||
90 | {1, 2}, {0, 1}, {0, 1}, {0, 1}, | ||
91 | {1, 2}, {0, 1}, {0, 1}, {0, 1}, | ||
92 | {1, 2}, {0, 1}, {0, 1}, {0, 1}, | ||
93 | {0, 1}, {0, 1}, {0, 1}, {0, 1}, | ||
94 | {0, 1}, {0, 1}, {0, 1}, {0, 1}, | ||
95 | {0, 1}, {0, 1}, {0, 1}, {0, 1}, | ||
96 | {0, 1}, {0, 1}, {0, 1}, {0, 1}, | ||
97 | }; | ||
98 | |||
99 | static void __init armada_38x_get_clk_ratio( | ||
100 | void __iomem *sar, int id, int *mult, int *div) | ||
101 | { | ||
102 | u32 opt = ((readl(sar) >> SAR_A380_CPU_DDR_L2_FREQ_OPT) & | ||
103 | SAR_A380_CPU_DDR_L2_FREQ_OPT_MASK); | ||
104 | |||
105 | switch (id) { | ||
106 | case A380_CPU_TO_L2: | ||
107 | *mult = armada_38x_cpu_l2_ratios[opt][0]; | ||
108 | *div = armada_38x_cpu_l2_ratios[opt][1]; | ||
109 | break; | ||
110 | case A380_CPU_TO_DDR: | ||
111 | *mult = armada_38x_cpu_ddr_ratios[opt][0]; | ||
112 | *div = armada_38x_cpu_ddr_ratios[opt][1]; | ||
113 | break; | ||
114 | } | ||
115 | } | ||
116 | |||
117 | static const struct coreclk_soc_desc armada_38x_coreclks = { | ||
118 | .get_tclk_freq = armada_38x_get_tclk_freq, | ||
119 | .get_cpu_freq = armada_38x_get_cpu_freq, | ||
120 | .get_clk_ratio = armada_38x_get_clk_ratio, | ||
121 | .ratios = armada_38x_coreclk_ratios, | ||
122 | .num_ratios = ARRAY_SIZE(armada_38x_coreclk_ratios), | ||
123 | }; | ||
124 | |||
125 | static void __init armada_38x_coreclk_init(struct device_node *np) | ||
126 | { | ||
127 | mvebu_coreclk_setup(np, &armada_38x_coreclks); | ||
128 | } | ||
129 | CLK_OF_DECLARE(armada_38x_core_clk, "marvell,armada-380-core-clock", | ||
130 | armada_38x_coreclk_init); | ||
131 | |||
132 | /* | ||
133 | * Clock Gating Control | ||
134 | */ | ||
135 | static const struct clk_gating_soc_desc armada_38x_gating_desc[] __initconst = { | ||
136 | { "audio", NULL, 0 }, | ||
137 | { "ge2", NULL, 2 }, | ||
138 | { "ge1", NULL, 3 }, | ||
139 | { "ge0", NULL, 4 }, | ||
140 | { "pex1", NULL, 5 }, | ||
141 | { "pex2", NULL, 6 }, | ||
142 | { "pex3", NULL, 7 }, | ||
143 | { "pex0", NULL, 8 }, | ||
144 | { "usb3h0", NULL, 9 }, | ||
145 | { "usb3h1", NULL, 10 }, | ||
146 | { "usb3d", NULL, 11 }, | ||
147 | { "bm", NULL, 13 }, | ||
148 | { "crypto0z", NULL, 14 }, | ||
149 | { "sata0", NULL, 15 }, | ||
150 | { "crypto1z", NULL, 16 }, | ||
151 | { "sdio", NULL, 17 }, | ||
152 | { "usb2", NULL, 18 }, | ||
153 | { "crypto1", NULL, 21 }, | ||
154 | { "xor0", NULL, 22 }, | ||
155 | { "crypto0", NULL, 23 }, | ||
156 | { "tdm", NULL, 25 }, | ||
157 | { "xor1", NULL, 28 }, | ||
158 | { "sata1", NULL, 30 }, | ||
159 | { } | ||
160 | }; | ||
161 | |||
162 | static void __init armada_38x_clk_gating_init(struct device_node *np) | ||
163 | { | ||
164 | mvebu_clk_gating_setup(np, armada_38x_gating_desc); | ||
165 | } | ||
166 | CLK_OF_DECLARE(armada_38x_clk_gating, "marvell,armada-380-gating-clock", | ||
167 | armada_38x_clk_gating_init); | ||