2 * Marvell Kirkwood SoC clocks
4 * Copyright (C) 2012 Marvell
6 * Gregory CLEMENT <gregory.clement@free-electrons.com>
7 * Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
8 * Andrew Lunn <andrew@lunn.ch>
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.
15 #include <linux/kernel.h>
16 #include <linux/slab.h>
17 #include <linux/clk-provider.h>
20 #include <linux/of_address.h>
26 * Kirkwood PLL sample-at-reset configuration
27 * (6180 has different SAR layout than other Kirkwood SoCs)
29 * SAR0[4:3,22,1] : CPU frequency (6281,6292,6282)
40 * SAR0[19,10:9] : CPU to L2 Clock divider ratio (6281,6292,6282)
46 * SAR0[8:5] : CPU to DDR DRAM Clock divider ratio (6281,6292,6282)
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]
61 * SAR0[21] : TCLK frequency
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
81 enum { KIRKWOOD_CPU_TO_L2
, KIRKWOOD_CPU_TO_DDR
};
83 static const struct coreclk_ratio kirkwood_coreclk_ratios
[] __initconst
= {
84 { .id
= KIRKWOOD_CPU_TO_L2
, .name
= "l2clk", },
85 { .id
= KIRKWOOD_CPU_TO_DDR
, .name
= "ddrclk", }
88 static u32 __init
kirkwood_get_tclk_freq(void __iomem
*sar
)
90 u32 opt
= (readl(sar
) >> SAR_KIRKWOOD_TCLK_FREQ
) &
91 SAR_KIRKWOOD_TCLK_FREQ_MASK
;
92 return (opt
) ? 166666667 : 200000000;
95 static const u32 kirkwood_cpu_freqs
[] __initconst
= {
110 static u32 __init
kirkwood_get_cpu_freq(void __iomem
*sar
)
112 u32 opt
= SAR_KIRKWOOD_CPU_FREQ(readl(sar
));
113 return kirkwood_cpu_freqs
[opt
];
116 static 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 }
121 static 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 }
128 static void __init
kirkwood_get_clk_ratio(
129 void __iomem
*sar
, int id
, int *mult
, int *div
)
132 case KIRKWOOD_CPU_TO_L2
:
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];
139 case KIRKWOOD_CPU_TO_DDR
:
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];
150 static const u32 mv88f6180_cpu_freqs
[] __initconst
= {
157 static u32 __init
mv88f6180_get_cpu_freq(void __iomem
*sar
)
159 u32 opt
= (readl(sar
) >> SAR_MV88F6180_CLK
) & SAR_MV88F6180_CLK_MASK
;
160 return mv88f6180_cpu_freqs
[opt
];
163 static 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 }
168 static void __init
mv88f6180_get_clk_ratio(
169 void __iomem
*sar
, int id
, int *mult
, int *div
)
172 case KIRKWOOD_CPU_TO_L2
:
174 /* mv88f6180 has a fixed 1:2 CPU-to-L2 ratio */
179 case KIRKWOOD_CPU_TO_DDR
:
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];
190 static 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
),
198 static 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
),
207 * Clock Gating Control
210 static 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 },
231 * Clock Muxing Control
234 struct clk_muxing_soc_desc
{
236 const char **parents
;
243 struct clk_muxing_ctrl
{
249 static const char *powersave_parents
[] = {
254 static const struct clk_muxing_soc_desc kirkwood_mux_desc
[] __initconst
= {
255 { "powersave", powersave_parents
, ARRAY_SIZE(powersave_parents
),
259 static struct clk
*clk_muxing_get_src(
260 struct of_phandle_args
*clkspec
, void *data
)
262 struct clk_muxing_ctrl
*ctrl
= (struct clk_muxing_ctrl
*)data
;
265 if (clkspec
->args_count
< 1)
266 return ERR_PTR(-EINVAL
);
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
];
274 return ERR_PTR(-ENODEV
);
277 static void __init
kirkwood_clk_muxing_setup(struct device_node
*np
,
278 const struct clk_muxing_soc_desc
*desc
)
280 struct clk_muxing_ctrl
*ctrl
;
284 base
= of_iomap(np
, 0);
288 ctrl
= kzalloc(sizeof(*ctrl
), GFP_KERNEL
);
292 /* lock must already be initialized */
293 ctrl
->lock
= &ctrl_gating_lock
;
295 /* Count, allocate, and register clock muxes */
296 for (n
= 0; desc
[n
].name
;)
300 ctrl
->muxes
= kcalloc(ctrl
->num_muxes
, sizeof(struct clk
*),
302 if (WARN_ON(!ctrl
->muxes
))
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
]));
313 of_clk_add_provider(np
, clk_muxing_get_src
, ctrl
);
322 static void __init
kirkwood_clk_init(struct device_node
*np
)
324 struct device_node
*cgnp
=
325 of_find_compatible_node(NULL
, NULL
, "marvell,kirkwood-gating-clock");
328 if (of_device_is_compatible(np
, "marvell,mv88f6180-core-clock"))
329 mvebu_coreclk_setup(np
, &mv88f6180_coreclks
);
331 mvebu_coreclk_setup(np
, &kirkwood_coreclks
);
334 mvebu_clk_gating_setup(cgnp
, kirkwood_gating_desc
);
335 kirkwood_clk_muxing_setup(cgnp
, kirkwood_mux_desc
);
338 CLK_OF_DECLARE(kirkwood_clk
, "marvell,kirkwood-core-clock",
340 CLK_OF_DECLARE(mv88f6180_clk
, "marvell,mv88f6180-core-clock",