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