Merge tag 'f2fs-for-4.21' of git://git.kernel.org/pub/scm/linux/kernel/git/jaegeuk...
[linux-2.6-block.git] / drivers / clk / mvebu / kirkwood.c
CommitLineData
c3828949 1// SPDX-License-Identifier: GPL-2.0
e89406c9
SH
2/*
3 * Marvell Kirkwood SoC clocks
4 *
5 * Copyright (C) 2012 Marvell
6 *
7 * Gregory CLEMENT <gregory.clement@free-electrons.com>
8 * Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
9 * Andrew Lunn <andrew@lunn.ch>
10 *
e89406c9
SH
11 */
12
13#include <linux/kernel.h>
e8e8a9b0 14#include <linux/slab.h>
e89406c9
SH
15#include <linux/clk-provider.h>
16#include <linux/io.h>
17#include <linux/of.h>
e8e8a9b0 18#include <linux/of_address.h>
e89406c9
SH
19#include "common.h"
20
21/*
22 * Core Clocks
23 *
24 * Kirkwood PLL sample-at-reset configuration
25 * (6180 has different SAR layout than other Kirkwood SoCs)
26 *
27 * SAR0[4:3,22,1] : CPU frequency (6281,6292,6282)
28 * 4 = 600 MHz
29 * 6 = 800 MHz
30 * 7 = 1000 MHz
31 * 9 = 1200 MHz
32 * 12 = 1500 MHz
33 * 13 = 1600 MHz
34 * 14 = 1800 MHz
35 * 15 = 2000 MHz
36 * others reserved.
37 *
38 * SAR0[19,10:9] : CPU to L2 Clock divider ratio (6281,6292,6282)
39 * 1 = (1/2) * CPU
40 * 3 = (1/3) * CPU
41 * 5 = (1/4) * CPU
42 * others reserved.
43 *
44 * SAR0[8:5] : CPU to DDR DRAM Clock divider ratio (6281,6292,6282)
45 * 2 = (1/2) * CPU
46 * 4 = (1/3) * CPU
47 * 6 = (1/4) * CPU
48 * 7 = (2/9) * CPU
49 * 8 = (1/5) * CPU
50 * 9 = (1/6) * CPU
51 * others reserved.
52 *
53 * SAR0[4:2] : Kirkwood 6180 cpu/l2/ddr clock configuration (6180 only)
54 * 5 = [CPU = 600 MHz, L2 = (1/2) * CPU, DDR = 200 MHz = (1/3) * CPU]
55 * 6 = [CPU = 800 MHz, L2 = (1/2) * CPU, DDR = 200 MHz = (1/4) * CPU]
56 * 7 = [CPU = 1000 MHz, L2 = (1/2) * CPU, DDR = 200 MHz = (1/5) * CPU]
57 * others reserved.
58 *
59 * SAR0[21] : TCLK frequency
60 * 0 = 200 MHz
61 * 1 = 166 MHz
62 * others reserved.
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
847b1c00 81static const struct coreclk_ratio kirkwood_coreclk_ratios[] __initconst = {
e89406c9
SH
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
847b1c00 93static const u32 kirkwood_cpu_freqs[] __initconst = {
e89406c9
SH
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
847b1c00 114static const int kirkwood_cpu_l2_ratios[8][2] __initconst = {
e89406c9
SH
115 { 0, 1 }, { 1, 2 }, { 0, 1 }, { 1, 3 },
116 { 0, 1 }, { 1, 4 }, { 0, 1 }, { 0, 1 }
117};
118
847b1c00 119static const int kirkwood_cpu_ddr_ratios[16][2] __initconst = {
e89406c9
SH
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
847b1c00 148static const u32 mv88f6180_cpu_freqs[] __initconst = {
e89406c9
SH
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
847b1c00 161static const int mv88f6180_cpu_ddr_ratios[8][2] __initconst = {
e89406c9
SH
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 /* mv88f6180 has a fixed 1:2 CPU-to-L2 ratio */
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 const struct coreclk_soc_desc kirkwood_coreclks = {
189 .get_tclk_freq = kirkwood_get_tclk_freq,
190 .get_cpu_freq = kirkwood_get_cpu_freq,
191 .get_clk_ratio = kirkwood_get_clk_ratio,
192 .ratios = kirkwood_coreclk_ratios,
193 .num_ratios = ARRAY_SIZE(kirkwood_coreclk_ratios),
194};
195
e89406c9
SH
196static const struct coreclk_soc_desc mv88f6180_coreclks = {
197 .get_tclk_freq = kirkwood_get_tclk_freq,
198 .get_cpu_freq = mv88f6180_get_cpu_freq,
199 .get_clk_ratio = mv88f6180_get_clk_ratio,
200 .ratios = kirkwood_coreclk_ratios,
201 .num_ratios = ARRAY_SIZE(kirkwood_coreclk_ratios),
202};
203
e89406c9
SH
204/*
205 * Clock Gating Control
206 */
207
847b1c00 208static const struct clk_gating_soc_desc kirkwood_gating_desc[] __initconst = {
e89406c9
SH
209 { "ge0", NULL, 0, 0 },
210 { "pex0", NULL, 2, 0 },
211 { "usb0", NULL, 3, 0 },
212 { "sdio", NULL, 4, 0 },
213 { "tsu", NULL, 5, 0 },
214 { "runit", NULL, 7, 0 },
215 { "xor0", NULL, 8, 0 },
216 { "audio", NULL, 9, 0 },
e89406c9
SH
217 { "sata0", NULL, 14, 0 },
218 { "sata1", NULL, 15, 0 },
219 { "xor1", NULL, 16, 0 },
220 { "crypto", NULL, 17, 0 },
221 { "pex1", NULL, 18, 0 },
222 { "ge1", NULL, 19, 0 },
223 { "tdm", NULL, 20, 0 },
224 { }
225};
226
e8e8a9b0
MT
227
228/*
229 * Clock Muxing Control
230 */
231
232struct clk_muxing_soc_desc {
233 const char *name;
234 const char **parents;
235 int num_parents;
236 int shift;
237 int width;
238 unsigned long flags;
239};
240
241struct clk_muxing_ctrl {
242 spinlock_t *lock;
243 struct clk **muxes;
244 int num_muxes;
245};
246
10529938
MT
247static const char *powersave_parents[] = {
248 "cpuclk",
249 "ddrclk",
250};
251
252static const struct clk_muxing_soc_desc kirkwood_mux_desc[] __initconst = {
253 { "powersave", powersave_parents, ARRAY_SIZE(powersave_parents),
254 11, 1, 0 },
255};
256
e8e8a9b0
MT
257static struct clk *clk_muxing_get_src(
258 struct of_phandle_args *clkspec, void *data)
259{
260 struct clk_muxing_ctrl *ctrl = (struct clk_muxing_ctrl *)data;
261 int n;
262
263 if (clkspec->args_count < 1)
264 return ERR_PTR(-EINVAL);
265
266 for (n = 0; n < ctrl->num_muxes; n++) {
267 struct clk_mux *mux =
268 to_clk_mux(__clk_get_hw(ctrl->muxes[n]));
269 if (clkspec->args[0] == mux->shift)
270 return ctrl->muxes[n];
271 }
272 return ERR_PTR(-ENODEV);
273}
274
275static void __init kirkwood_clk_muxing_setup(struct device_node *np,
276 const struct clk_muxing_soc_desc *desc)
277{
278 struct clk_muxing_ctrl *ctrl;
279 void __iomem *base;
280 int n;
281
282 base = of_iomap(np, 0);
283 if (WARN_ON(!base))
284 return;
285
286 ctrl = kzalloc(sizeof(*ctrl), GFP_KERNEL);
287 if (WARN_ON(!ctrl))
288 goto ctrl_out;
289
290 /* lock must already be initialized */
291 ctrl->lock = &ctrl_gating_lock;
292
293 /* Count, allocate, and register clock muxes */
294 for (n = 0; desc[n].name;)
295 n++;
296
297 ctrl->num_muxes = n;
298 ctrl->muxes = kcalloc(ctrl->num_muxes, sizeof(struct clk *),
299 GFP_KERNEL);
300 if (WARN_ON(!ctrl->muxes))
301 goto muxes_out;
302
303 for (n = 0; n < ctrl->num_muxes; n++) {
304 ctrl->muxes[n] = clk_register_mux(NULL, desc[n].name,
305 desc[n].parents, desc[n].num_parents,
306 desc[n].flags, base, desc[n].shift,
307 desc[n].width, desc[n].flags, ctrl->lock);
308 WARN_ON(IS_ERR(ctrl->muxes[n]));
309 }
310
311 of_clk_add_provider(np, clk_muxing_get_src, ctrl);
312
313 return;
314muxes_out:
315 kfree(ctrl);
316ctrl_out:
317 iounmap(base);
318}
319
58d516ae 320static void __init kirkwood_clk_init(struct device_node *np)
e89406c9 321{
58d516ae
SH
322 struct device_node *cgnp =
323 of_find_compatible_node(NULL, NULL, "marvell,kirkwood-gating-clock");
324
325
326 if (of_device_is_compatible(np, "marvell,mv88f6180-core-clock"))
327 mvebu_coreclk_setup(np, &mv88f6180_coreclks);
328 else
329 mvebu_coreclk_setup(np, &kirkwood_coreclks);
330
10529938 331 if (cgnp) {
58d516ae 332 mvebu_clk_gating_setup(cgnp, kirkwood_gating_desc);
10529938
MT
333 kirkwood_clk_muxing_setup(cgnp, kirkwood_mux_desc);
334 }
e89406c9 335}
58d516ae
SH
336CLK_OF_DECLARE(kirkwood_clk, "marvell,kirkwood-core-clock",
337 kirkwood_clk_init);
338CLK_OF_DECLARE(mv88f6180_clk, "marvell,mv88f6180-core-clock",
339 kirkwood_clk_init);