1
2
3
4
5
6
7
8
9
10
11
12
13
14
15#include <linux/kernel.h>
16#include <linux/slab.h>
17#include <linux/clk-provider.h>
18#include <linux/io.h>
19#include <linux/of.h>
20#include <linux/of_address.h>
21#include "common.h"
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67#define SAR_KIRKWOOD_CPU_FREQ(x) \
68 (((x & (1 << 1)) >> 1) | \
69 ((x & (1 << 22)) >> 21) | \
70 ((x & (3 << 3)) >> 1))
71#define SAR_KIRKWOOD_L2_RATIO(x) \
72 (((x & (3 << 9)) >> 9) | \
73 (((x & (1 << 19)) >> 17)))
74#define SAR_KIRKWOOD_DDR_RATIO 5
75#define SAR_KIRKWOOD_DDR_RATIO_MASK 0xf
76#define SAR_MV88F6180_CLK 2
77#define SAR_MV88F6180_CLK_MASK 0x7
78#define SAR_KIRKWOOD_TCLK_FREQ 21
79#define SAR_KIRKWOOD_TCLK_FREQ_MASK 0x1
80
81enum { KIRKWOOD_CPU_TO_L2, KIRKWOOD_CPU_TO_DDR };
82
83static const struct coreclk_ratio kirkwood_coreclk_ratios[] __initconst = {
84 { .id = KIRKWOOD_CPU_TO_L2, .name = "l2clk", },
85 { .id = KIRKWOOD_CPU_TO_DDR, .name = "ddrclk", }
86};
87
88static u32 __init kirkwood_get_tclk_freq(void __iomem *sar)
89{
90 u32 opt = (readl(sar) >> SAR_KIRKWOOD_TCLK_FREQ) &
91 SAR_KIRKWOOD_TCLK_FREQ_MASK;
92 return (opt) ? 166666667 : 200000000;
93}
94
95static const u32 kirkwood_cpu_freqs[] __initconst = {
96 0, 0, 0, 0,
97 600000000,
98 0,
99 800000000,
100 1000000000,
101 0,
102 1200000000,
103 0, 0,
104 1500000000,
105 1600000000,
106 1800000000,
107 2000000000
108};
109
110static u32 __init kirkwood_get_cpu_freq(void __iomem *sar)
111{
112 u32 opt = SAR_KIRKWOOD_CPU_FREQ(readl(sar));
113 return kirkwood_cpu_freqs[opt];
114}
115
116static const int kirkwood_cpu_l2_ratios[8][2] __initconst = {
117 { 0, 1 }, { 1, 2 }, { 0, 1 }, { 1, 3 },
118 { 0, 1 }, { 1, 4 }, { 0, 1 }, { 0, 1 }
119};
120
121static const int kirkwood_cpu_ddr_ratios[16][2] __initconst = {
122 { 0, 1 }, { 0, 1 }, { 1, 2 }, { 0, 1 },
123 { 1, 3 }, { 0, 1 }, { 1, 4 }, { 2, 9 },
124 { 1, 5 }, { 1, 6 }, { 0, 1 }, { 0, 1 },
125 { 0, 1 }, { 0, 1 }, { 0, 1 }, { 0, 1 }
126};
127
128static void __init kirkwood_get_clk_ratio(
129 void __iomem *sar, int id, int *mult, int *div)
130{
131 switch (id) {
132 case KIRKWOOD_CPU_TO_L2:
133 {
134 u32 opt = SAR_KIRKWOOD_L2_RATIO(readl(sar));
135 *mult = kirkwood_cpu_l2_ratios[opt][0];
136 *div = kirkwood_cpu_l2_ratios[opt][1];
137 break;
138 }
139 case KIRKWOOD_CPU_TO_DDR:
140 {
141 u32 opt = (readl(sar) >> SAR_KIRKWOOD_DDR_RATIO) &
142 SAR_KIRKWOOD_DDR_RATIO_MASK;
143 *mult = kirkwood_cpu_ddr_ratios[opt][0];
144 *div = kirkwood_cpu_ddr_ratios[opt][1];
145 break;
146 }
147 }
148}
149
150static const u32 mv88f6180_cpu_freqs[] __initconst = {
151 0, 0, 0, 0, 0,
152 600000000,
153 800000000,
154 1000000000
155};
156
157static u32 __init mv88f6180_get_cpu_freq(void __iomem *sar)
158{
159 u32 opt = (readl(sar) >> SAR_MV88F6180_CLK) & SAR_MV88F6180_CLK_MASK;
160 return mv88f6180_cpu_freqs[opt];
161}
162
163static const int mv88f6180_cpu_ddr_ratios[8][2] __initconst = {
164 { 0, 1 }, { 0, 1 }, { 0, 1 }, { 0, 1 },
165 { 0, 1 }, { 1, 3 }, { 1, 4 }, { 1, 5 }
166};
167
168static void __init mv88f6180_get_clk_ratio(
169 void __iomem *sar, int id, int *mult, int *div)
170{
171 switch (id) {
172 case KIRKWOOD_CPU_TO_L2:
173 {
174
175 *mult = 1;
176 *div = 2;
177 break;
178 }
179 case KIRKWOOD_CPU_TO_DDR:
180 {
181 u32 opt = (readl(sar) >> SAR_MV88F6180_CLK) &
182 SAR_MV88F6180_CLK_MASK;
183 *mult = mv88f6180_cpu_ddr_ratios[opt][0];
184 *div = mv88f6180_cpu_ddr_ratios[opt][1];
185 break;
186 }
187 }
188}
189
190static const struct coreclk_soc_desc kirkwood_coreclks = {
191 .get_tclk_freq = kirkwood_get_tclk_freq,
192 .get_cpu_freq = kirkwood_get_cpu_freq,
193 .get_clk_ratio = kirkwood_get_clk_ratio,
194 .ratios = kirkwood_coreclk_ratios,
195 .num_ratios = ARRAY_SIZE(kirkwood_coreclk_ratios),
196};
197
198static const struct coreclk_soc_desc mv88f6180_coreclks = {
199 .get_tclk_freq = kirkwood_get_tclk_freq,
200 .get_cpu_freq = mv88f6180_get_cpu_freq,
201 .get_clk_ratio = mv88f6180_get_clk_ratio,
202 .ratios = kirkwood_coreclk_ratios,
203 .num_ratios = ARRAY_SIZE(kirkwood_coreclk_ratios),
204};
205
206
207
208
209
210static const struct clk_gating_soc_desc kirkwood_gating_desc[] __initconst = {
211 { "ge0", NULL, 0, 0 },
212 { "pex0", NULL, 2, 0 },
213 { "usb0", NULL, 3, 0 },
214 { "sdio", NULL, 4, 0 },
215 { "tsu", NULL, 5, 0 },
216 { "runit", NULL, 7, 0 },
217 { "xor0", NULL, 8, 0 },
218 { "audio", NULL, 9, 0 },
219 { "sata0", NULL, 14, 0 },
220 { "sata1", NULL, 15, 0 },
221 { "xor1", NULL, 16, 0 },
222 { "crypto", NULL, 17, 0 },
223 { "pex1", NULL, 18, 0 },
224 { "ge1", NULL, 19, 0 },
225 { "tdm", NULL, 20, 0 },
226 { }
227};
228
229
230
231
232
233
234struct clk_muxing_soc_desc {
235 const char *name;
236 const char **parents;
237 int num_parents;
238 int shift;
239 int width;
240 unsigned long flags;
241};
242
243struct clk_muxing_ctrl {
244 spinlock_t *lock;
245 struct clk **muxes;
246 int num_muxes;
247};
248
249static const char *powersave_parents[] = {
250 "cpuclk",
251 "ddrclk",
252};
253
254static const struct clk_muxing_soc_desc kirkwood_mux_desc[] __initconst = {
255 { "powersave", powersave_parents, ARRAY_SIZE(powersave_parents),
256 11, 1, 0 },
257};
258
259static struct clk *clk_muxing_get_src(
260 struct of_phandle_args *clkspec, void *data)
261{
262 struct clk_muxing_ctrl *ctrl = (struct clk_muxing_ctrl *)data;
263 int n;
264
265 if (clkspec->args_count < 1)
266 return ERR_PTR(-EINVAL);
267
268 for (n = 0; n < ctrl->num_muxes; n++) {
269 struct clk_mux *mux =
270 to_clk_mux(__clk_get_hw(ctrl->muxes[n]));
271 if (clkspec->args[0] == mux->shift)
272 return ctrl->muxes[n];
273 }
274 return ERR_PTR(-ENODEV);
275}
276
277static void __init kirkwood_clk_muxing_setup(struct device_node *np,
278 const struct clk_muxing_soc_desc *desc)
279{
280 struct clk_muxing_ctrl *ctrl;
281 void __iomem *base;
282 int n;
283
284 base = of_iomap(np, 0);
285 if (WARN_ON(!base))
286 return;
287
288 ctrl = kzalloc(sizeof(*ctrl), GFP_KERNEL);
289 if (WARN_ON(!ctrl))
290 goto ctrl_out;
291
292
293 ctrl->lock = &ctrl_gating_lock;
294
295
296 for (n = 0; desc[n].name;)
297 n++;
298
299 ctrl->num_muxes = n;
300 ctrl->muxes = kcalloc(ctrl->num_muxes, sizeof(struct clk *),
301 GFP_KERNEL);
302 if (WARN_ON(!ctrl->muxes))
303 goto muxes_out;
304
305 for (n = 0; n < ctrl->num_muxes; n++) {
306 ctrl->muxes[n] = clk_register_mux(NULL, desc[n].name,
307 desc[n].parents, desc[n].num_parents,
308 desc[n].flags, base, desc[n].shift,
309 desc[n].width, desc[n].flags, ctrl->lock);
310 WARN_ON(IS_ERR(ctrl->muxes[n]));
311 }
312
313 of_clk_add_provider(np, clk_muxing_get_src, ctrl);
314
315 return;
316muxes_out:
317 kfree(ctrl);
318ctrl_out:
319 iounmap(base);
320}
321
322static void __init kirkwood_clk_init(struct device_node *np)
323{
324 struct device_node *cgnp =
325 of_find_compatible_node(NULL, NULL, "marvell,kirkwood-gating-clock");
326
327
328 if (of_device_is_compatible(np, "marvell,mv88f6180-core-clock"))
329 mvebu_coreclk_setup(np, &mv88f6180_coreclks);
330 else
331 mvebu_coreclk_setup(np, &kirkwood_coreclks);
332
333 if (cgnp) {
334 mvebu_clk_gating_setup(cgnp, kirkwood_gating_desc);
335 kirkwood_clk_muxing_setup(cgnp, kirkwood_mux_desc);
336 }
337}
338CLK_OF_DECLARE(kirkwood_clk, "marvell,kirkwood-core-clock",
339 kirkwood_clk_init);
340CLK_OF_DECLARE(mv88f6180_clk, "marvell,mv88f6180-core-clock",
341 kirkwood_clk_init);
342