qed: Add slowpath L2 support
[deliverable/linux.git] / drivers / clk / mvebu / kirkwood.c
CommitLineData
e89406c9
SH
1/*
2 * Marvell Kirkwood SoC clocks
3 *
4 * Copyright (C) 2012 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>
e8e8a9b0 16#include <linux/slab.h>
e89406c9
SH
17#include <linux/clk-provider.h>
18#include <linux/io.h>
19#include <linux/of.h>
e8e8a9b0 20#include <linux/of_address.h>
e89406c9
SH
21#include "common.h"
22
23/*
24 * Core Clocks
25 *
26 * Kirkwood PLL sample-at-reset configuration
27 * (6180 has different SAR layout than other Kirkwood SoCs)
28 *
29 * SAR0[4:3,22,1] : CPU frequency (6281,6292,6282)
30 * 4 = 600 MHz
31 * 6 = 800 MHz
32 * 7 = 1000 MHz
33 * 9 = 1200 MHz
34 * 12 = 1500 MHz
35 * 13 = 1600 MHz
36 * 14 = 1800 MHz
37 * 15 = 2000 MHz
38 * others reserved.
39 *
40 * SAR0[19,10:9] : CPU to L2 Clock divider ratio (6281,6292,6282)
41 * 1 = (1/2) * CPU
42 * 3 = (1/3) * CPU
43 * 5 = (1/4) * CPU
44 * others reserved.
45 *
46 * SAR0[8:5] : CPU to DDR DRAM Clock divider ratio (6281,6292,6282)
47 * 2 = (1/2) * CPU
48 * 4 = (1/3) * CPU
49 * 6 = (1/4) * CPU
50 * 7 = (2/9) * CPU
51 * 8 = (1/5) * CPU
52 * 9 = (1/6) * CPU
53 * others reserved.
54 *
55 * SAR0[4:2] : Kirkwood 6180 cpu/l2/ddr clock configuration (6180 only)
56 * 5 = [CPU = 600 MHz, L2 = (1/2) * CPU, DDR = 200 MHz = (1/3) * CPU]
57 * 6 = [CPU = 800 MHz, L2 = (1/2) * CPU, DDR = 200 MHz = (1/4) * CPU]
58 * 7 = [CPU = 1000 MHz, L2 = (1/2) * CPU, DDR = 200 MHz = (1/5) * CPU]
59 * others reserved.
60 *
61 * SAR0[21] : TCLK frequency
62 * 0 = 200 MHz
63 * 1 = 166 MHz
64 * others reserved.
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
847b1c00 83static const struct coreclk_ratio kirkwood_coreclk_ratios[] __initconst = {
e89406c9
SH
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
847b1c00 95static const u32 kirkwood_cpu_freqs[] __initconst = {
e89406c9
SH
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
847b1c00 116static const int kirkwood_cpu_l2_ratios[8][2] __initconst = {
e89406c9
SH
117 { 0, 1 }, { 1, 2 }, { 0, 1 }, { 1, 3 },
118 { 0, 1 }, { 1, 4 }, { 0, 1 }, { 0, 1 }
119};
120
847b1c00 121static const int kirkwood_cpu_ddr_ratios[16][2] __initconst = {
e89406c9
SH
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
847b1c00 150static const u32 mv88f6180_cpu_freqs[] __initconst = {
e89406c9
SH
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
847b1c00 163static const int mv88f6180_cpu_ddr_ratios[8][2] __initconst = {
e89406c9
SH
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 /* mv88f6180 has a fixed 1:2 CPU-to-L2 ratio */
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
e89406c9
SH
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
e89406c9
SH
206/*
207 * Clock Gating Control
208 */
209
847b1c00 210static const struct clk_gating_soc_desc kirkwood_gating_desc[] __initconst = {
e89406c9
SH
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 },
e89406c9
SH
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
e8e8a9b0
MT
229
230/*
231 * Clock Muxing Control
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
10529938
MT
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
e8e8a9b0
MT
259#define to_clk_mux(_hw) container_of(_hw, struct clk_mux, hw)
260
261static struct clk *clk_muxing_get_src(
262 struct of_phandle_args *clkspec, void *data)
263{
264 struct clk_muxing_ctrl *ctrl = (struct clk_muxing_ctrl *)data;
265 int n;
266
267 if (clkspec->args_count < 1)
268 return ERR_PTR(-EINVAL);
269
270 for (n = 0; n < ctrl->num_muxes; n++) {
271 struct clk_mux *mux =
272 to_clk_mux(__clk_get_hw(ctrl->muxes[n]));
273 if (clkspec->args[0] == mux->shift)
274 return ctrl->muxes[n];
275 }
276 return ERR_PTR(-ENODEV);
277}
278
279static void __init kirkwood_clk_muxing_setup(struct device_node *np,
280 const struct clk_muxing_soc_desc *desc)
281{
282 struct clk_muxing_ctrl *ctrl;
283 void __iomem *base;
284 int n;
285
286 base = of_iomap(np, 0);
287 if (WARN_ON(!base))
288 return;
289
290 ctrl = kzalloc(sizeof(*ctrl), GFP_KERNEL);
291 if (WARN_ON(!ctrl))
292 goto ctrl_out;
293
294 /* lock must already be initialized */
295 ctrl->lock = &ctrl_gating_lock;
296
297 /* Count, allocate, and register clock muxes */
298 for (n = 0; desc[n].name;)
299 n++;
300
301 ctrl->num_muxes = n;
302 ctrl->muxes = kcalloc(ctrl->num_muxes, sizeof(struct clk *),
303 GFP_KERNEL);
304 if (WARN_ON(!ctrl->muxes))
305 goto muxes_out;
306
307 for (n = 0; n < ctrl->num_muxes; n++) {
308 ctrl->muxes[n] = clk_register_mux(NULL, desc[n].name,
309 desc[n].parents, desc[n].num_parents,
310 desc[n].flags, base, desc[n].shift,
311 desc[n].width, desc[n].flags, ctrl->lock);
312 WARN_ON(IS_ERR(ctrl->muxes[n]));
313 }
314
315 of_clk_add_provider(np, clk_muxing_get_src, ctrl);
316
317 return;
318muxes_out:
319 kfree(ctrl);
320ctrl_out:
321 iounmap(base);
322}
323
58d516ae 324static void __init kirkwood_clk_init(struct device_node *np)
e89406c9 325{
58d516ae
SH
326 struct device_node *cgnp =
327 of_find_compatible_node(NULL, NULL, "marvell,kirkwood-gating-clock");
328
329
330 if (of_device_is_compatible(np, "marvell,mv88f6180-core-clock"))
331 mvebu_coreclk_setup(np, &mv88f6180_coreclks);
332 else
333 mvebu_coreclk_setup(np, &kirkwood_coreclks);
334
10529938 335 if (cgnp) {
58d516ae 336 mvebu_clk_gating_setup(cgnp, kirkwood_gating_desc);
10529938
MT
337 kirkwood_clk_muxing_setup(cgnp, kirkwood_mux_desc);
338 }
e89406c9 339}
58d516ae
SH
340CLK_OF_DECLARE(kirkwood_clk, "marvell,kirkwood-core-clock",
341 kirkwood_clk_init);
342CLK_OF_DECLARE(mv88f6180_clk, "marvell,mv88f6180-core-clock",
343 kirkwood_clk_init);
This page took 0.150541 seconds and 5 git commands to generate.