aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDaniel Thompson <daniel.thompson@linaro.org>2015-06-10 16:09:37 -0400
committerStephen Boyd <sboyd@codeaurora.org>2015-06-22 19:17:01 -0400
commit358bdf892f6bfacf20884b54a35ab038321f06f9 (patch)
treec4505e8178f562ebf7798a38cd03226f1c6e8cfb
parent41655239eaed741ac8da066bc43c2483c78e61ec (diff)
clk: stm32: Add clock driver for STM32F4[23]xxx devices
The driver supports decoding and statically modelling PLL state (i.e. we inherit state from bootloader) and provides support for all peripherals that support simple one-bit gated clocks. The covers all peripherals whose clocks come from the AHB, APB1 or APB2 buses. It has been tested on an STM32F429I-Discovery board. The clock counts for TIM2, USART1 and SYSTICK are all set correctly and the wall clock looks OK when checked with a stopwatch. I have also tested a prototype driver for the RNG hardware. The RNG clock is correctly enabled by the framework (also did inverse test and proved that by changing DT to configure the wrong clock bit then we observe the RNG driver to fail). Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org> Reviewed-by: Maxime Coquelin <mcoquelin.stm32@gmail.com> [sboyd@codeaurora.org: Silence sparse warnings] Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
-rw-r--r--drivers/clk/Makefile1
-rw-r--r--drivers/clk/clk-stm32f4.c380
2 files changed, 381 insertions, 0 deletions
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index 256977ed050a..fc789a07cb5f 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -39,6 +39,7 @@ obj-$(CONFIG_COMMON_CLK_S2MPS11) += clk-s2mps11.o
39obj-$(CONFIG_COMMON_CLK_SI5351) += clk-si5351.o 39obj-$(CONFIG_COMMON_CLK_SI5351) += clk-si5351.o
40obj-$(CONFIG_COMMON_CLK_SI570) += clk-si570.o 40obj-$(CONFIG_COMMON_CLK_SI570) += clk-si570.o
41obj-$(CONFIG_COMMON_CLK_CDCE925) += clk-cdce925.o 41obj-$(CONFIG_COMMON_CLK_CDCE925) += clk-cdce925.o
42obj-$(CONFIG_ARCH_STM32) += clk-stm32f4.o
42obj-$(CONFIG_CLK_TWL6040) += clk-twl6040.o 43obj-$(CONFIG_CLK_TWL6040) += clk-twl6040.o
43obj-$(CONFIG_ARCH_U300) += clk-u300.o 44obj-$(CONFIG_ARCH_U300) += clk-u300.o
44obj-$(CONFIG_ARCH_VT8500) += clk-vt8500.o 45obj-$(CONFIG_ARCH_VT8500) += clk-vt8500.o
diff --git a/drivers/clk/clk-stm32f4.c b/drivers/clk/clk-stm32f4.c
new file mode 100644
index 000000000000..b9b12a742970
--- /dev/null
+++ b/drivers/clk/clk-stm32f4.c
@@ -0,0 +1,380 @@
1/*
2 * Author: Daniel Thompson <daniel.thompson@linaro.org>
3 *
4 * Inspired by clk-asm9260.c .
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms and conditions of the GNU General Public License,
8 * version 2, as published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
13 * more details.
14 *
15 * You should have received a copy of the GNU General Public License along with
16 * this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19#include <linux/clk-provider.h>
20#include <linux/err.h>
21#include <linux/io.h>
22#include <linux/slab.h>
23#include <linux/spinlock.h>
24#include <linux/of.h>
25#include <linux/of_address.h>
26
27#define STM32F4_RCC_PLLCFGR 0x04
28#define STM32F4_RCC_CFGR 0x08
29#define STM32F4_RCC_AHB1ENR 0x30
30#define STM32F4_RCC_AHB2ENR 0x34
31#define STM32F4_RCC_AHB3ENR 0x38
32#define STM32F4_RCC_APB1ENR 0x40
33#define STM32F4_RCC_APB2ENR 0x44
34
35struct stm32f4_gate_data {
36 u8 offset;
37 u8 bit_idx;
38 const char *name;
39 const char *parent_name;
40 unsigned long flags;
41};
42
43static const struct stm32f4_gate_data stm32f4_gates[] __initconst = {
44 { STM32F4_RCC_AHB1ENR, 0, "gpioa", "ahb_div" },
45 { STM32F4_RCC_AHB1ENR, 1, "gpiob", "ahb_div" },
46 { STM32F4_RCC_AHB1ENR, 2, "gpioc", "ahb_div" },
47 { STM32F4_RCC_AHB1ENR, 3, "gpiod", "ahb_div" },
48 { STM32F4_RCC_AHB1ENR, 4, "gpioe", "ahb_div" },
49 { STM32F4_RCC_AHB1ENR, 5, "gpiof", "ahb_div" },
50 { STM32F4_RCC_AHB1ENR, 6, "gpiog", "ahb_div" },
51 { STM32F4_RCC_AHB1ENR, 7, "gpioh", "ahb_div" },
52 { STM32F4_RCC_AHB1ENR, 8, "gpioi", "ahb_div" },
53 { STM32F4_RCC_AHB1ENR, 9, "gpioj", "ahb_div" },
54 { STM32F4_RCC_AHB1ENR, 10, "gpiok", "ahb_div" },
55 { STM32F4_RCC_AHB1ENR, 12, "crc", "ahb_div" },
56 { STM32F4_RCC_AHB1ENR, 18, "bkpsra", "ahb_div" },
57 { STM32F4_RCC_AHB1ENR, 20, "ccmdatam", "ahb_div" },
58 { STM32F4_RCC_AHB1ENR, 21, "dma1", "ahb_div" },
59 { STM32F4_RCC_AHB1ENR, 22, "dma2", "ahb_div" },
60 { STM32F4_RCC_AHB1ENR, 23, "dma2d", "ahb_div" },
61 { STM32F4_RCC_AHB1ENR, 25, "ethmac", "ahb_div" },
62 { STM32F4_RCC_AHB1ENR, 26, "ethmactx", "ahb_div" },
63 { STM32F4_RCC_AHB1ENR, 27, "ethmacrx", "ahb_div" },
64 { STM32F4_RCC_AHB1ENR, 28, "ethmacptp", "ahb_div" },
65 { STM32F4_RCC_AHB1ENR, 29, "otghs", "ahb_div" },
66 { STM32F4_RCC_AHB1ENR, 30, "otghsulpi", "ahb_div" },
67
68 { STM32F4_RCC_AHB2ENR, 0, "dcmi", "ahb_div" },
69 { STM32F4_RCC_AHB2ENR, 4, "cryp", "ahb_div" },
70 { STM32F4_RCC_AHB2ENR, 5, "hash", "ahb_div" },
71 { STM32F4_RCC_AHB2ENR, 6, "rng", "pll48" },
72 { STM32F4_RCC_AHB2ENR, 7, "otgfs", "pll48" },
73
74 { STM32F4_RCC_AHB3ENR, 0, "fmc", "ahb_div",
75 CLK_IGNORE_UNUSED },
76
77 { STM32F4_RCC_APB1ENR, 0, "tim2", "apb1_mul" },
78 { STM32F4_RCC_APB1ENR, 1, "tim3", "apb1_mul" },
79 { STM32F4_RCC_APB1ENR, 2, "tim4", "apb1_mul" },
80 { STM32F4_RCC_APB1ENR, 3, "tim5", "apb1_mul" },
81 { STM32F4_RCC_APB1ENR, 4, "tim6", "apb1_mul" },
82 { STM32F4_RCC_APB1ENR, 5, "tim7", "apb1_mul" },
83 { STM32F4_RCC_APB1ENR, 6, "tim12", "apb1_mul" },
84 { STM32F4_RCC_APB1ENR, 7, "tim13", "apb1_mul" },
85 { STM32F4_RCC_APB1ENR, 8, "tim14", "apb1_mul" },
86 { STM32F4_RCC_APB1ENR, 11, "wwdg", "apb1_div" },
87 { STM32F4_RCC_APB1ENR, 14, "spi2", "apb1_div" },
88 { STM32F4_RCC_APB1ENR, 15, "spi3", "apb1_div" },
89 { STM32F4_RCC_APB1ENR, 17, "uart2", "apb1_div" },
90 { STM32F4_RCC_APB1ENR, 18, "uart3", "apb1_div" },
91 { STM32F4_RCC_APB1ENR, 19, "uart4", "apb1_div" },
92 { STM32F4_RCC_APB1ENR, 20, "uart5", "apb1_div" },
93 { STM32F4_RCC_APB1ENR, 21, "i2c1", "apb1_div" },
94 { STM32F4_RCC_APB1ENR, 22, "i2c2", "apb1_div" },
95 { STM32F4_RCC_APB1ENR, 23, "i2c3", "apb1_div" },
96 { STM32F4_RCC_APB1ENR, 25, "can1", "apb1_div" },
97 { STM32F4_RCC_APB1ENR, 26, "can2", "apb1_div" },
98 { STM32F4_RCC_APB1ENR, 28, "pwr", "apb1_div" },
99 { STM32F4_RCC_APB1ENR, 29, "dac", "apb1_div" },
100 { STM32F4_RCC_APB1ENR, 30, "uart7", "apb1_div" },
101 { STM32F4_RCC_APB1ENR, 31, "uart8", "apb1_div" },
102
103 { STM32F4_RCC_APB2ENR, 0, "tim1", "apb2_mul" },
104 { STM32F4_RCC_APB2ENR, 1, "tim8", "apb2_mul" },
105 { STM32F4_RCC_APB2ENR, 4, "usart1", "apb2_div" },
106 { STM32F4_RCC_APB2ENR, 5, "usart6", "apb2_div" },
107 { STM32F4_RCC_APB2ENR, 8, "adc1", "apb2_div" },
108 { STM32F4_RCC_APB2ENR, 9, "adc2", "apb2_div" },
109 { STM32F4_RCC_APB2ENR, 10, "adc3", "apb2_div" },
110 { STM32F4_RCC_APB2ENR, 11, "sdio", "pll48" },
111 { STM32F4_RCC_APB2ENR, 12, "spi1", "apb2_div" },
112 { STM32F4_RCC_APB2ENR, 13, "spi4", "apb2_div" },
113 { STM32F4_RCC_APB2ENR, 14, "syscfg", "apb2_div" },
114 { STM32F4_RCC_APB2ENR, 16, "tim9", "apb2_mul" },
115 { STM32F4_RCC_APB2ENR, 17, "tim10", "apb2_mul" },
116 { STM32F4_RCC_APB2ENR, 18, "tim11", "apb2_mul" },
117 { STM32F4_RCC_APB2ENR, 20, "spi5", "apb2_div" },
118 { STM32F4_RCC_APB2ENR, 21, "spi6", "apb2_div" },
119 { STM32F4_RCC_APB2ENR, 22, "sai1", "apb2_div" },
120 { STM32F4_RCC_APB2ENR, 26, "ltdc", "apb2_div" },
121};
122
123/*
124 * MAX_CLKS is the maximum value in the enumeration below plus the combined
125 * hweight of stm32f42xx_gate_map (plus one).
126 */
127#define MAX_CLKS 74
128
129enum { SYSTICK, FCLK };
130
131/*
132 * This bitmask tells us which bit offsets (0..192) on STM32F4[23]xxx
133 * have gate bits associated with them. Its combined hweight is 71.
134 */
135static const u64 stm32f42xx_gate_map[] = { 0x000000f17ef417ffull,
136 0x0000000000000001ull,
137 0x04777f33f6fec9ffull };
138
139static struct clk *clks[MAX_CLKS];
140static DEFINE_SPINLOCK(stm32f4_clk_lock);
141static void __iomem *base;
142
143/*
144 * "Multiplier" device for APBx clocks.
145 *
146 * The APBx dividers are power-of-two dividers and, if *not* running in 1:1
147 * mode, they also tap out the one of the low order state bits to run the
148 * timers. ST datasheets represent this feature as a (conditional) clock
149 * multiplier.
150 */
151struct clk_apb_mul {
152 struct clk_hw hw;
153 u8 bit_idx;
154};
155
156#define to_clk_apb_mul(_hw) container_of(_hw, struct clk_apb_mul, hw)
157
158static unsigned long clk_apb_mul_recalc_rate(struct clk_hw *hw,
159 unsigned long parent_rate)
160{
161 struct clk_apb_mul *am = to_clk_apb_mul(hw);
162
163 if (readl(base + STM32F4_RCC_CFGR) & BIT(am->bit_idx))
164 return parent_rate * 2;
165
166 return parent_rate;
167}
168
169static long clk_apb_mul_round_rate(struct clk_hw *hw, unsigned long rate,
170 unsigned long *prate)
171{
172 struct clk_apb_mul *am = to_clk_apb_mul(hw);
173 unsigned long mult = 1;
174
175 if (readl(base + STM32F4_RCC_CFGR) & BIT(am->bit_idx))
176 mult = 2;
177
178 if (__clk_get_flags(hw->clk) & CLK_SET_RATE_PARENT) {
179 unsigned long best_parent = rate / mult;
180
181 *prate =
182 __clk_round_rate(__clk_get_parent(hw->clk), best_parent);
183 }
184
185 return *prate * mult;
186}
187
188static int clk_apb_mul_set_rate(struct clk_hw *hw, unsigned long rate,
189 unsigned long parent_rate)
190{
191 /*
192 * We must report success but we can do so unconditionally because
193 * clk_apb_mul_round_rate returns values that ensure this call is a
194 * nop.
195 */
196
197 return 0;
198}
199
200static const struct clk_ops clk_apb_mul_factor_ops = {
201 .round_rate = clk_apb_mul_round_rate,
202 .set_rate = clk_apb_mul_set_rate,
203 .recalc_rate = clk_apb_mul_recalc_rate,
204};
205
206static struct clk *clk_register_apb_mul(struct device *dev, const char *name,
207 const char *parent_name,
208 unsigned long flags, u8 bit_idx)
209{
210 struct clk_apb_mul *am;
211 struct clk_init_data init;
212 struct clk *clk;
213
214 am = kzalloc(sizeof(*am), GFP_KERNEL);
215 if (!am)
216 return ERR_PTR(-ENOMEM);
217
218 am->bit_idx = bit_idx;
219 am->hw.init = &init;
220
221 init.name = name;
222 init.ops = &clk_apb_mul_factor_ops;
223 init.flags = flags;
224 init.parent_names = &parent_name;
225 init.num_parents = 1;
226
227 clk = clk_register(dev, &am->hw);
228
229 if (IS_ERR(clk))
230 kfree(am);
231
232 return clk;
233}
234
235/*
236 * Decode current PLL state and (statically) model the state we inherit from
237 * the bootloader.
238 */
239static void stm32f4_rcc_register_pll(const char *hse_clk, const char *hsi_clk)
240{
241 unsigned long pllcfgr = readl(base + STM32F4_RCC_PLLCFGR);
242
243 unsigned long pllm = pllcfgr & 0x3f;
244 unsigned long plln = (pllcfgr >> 6) & 0x1ff;
245 unsigned long pllp = BIT(((pllcfgr >> 16) & 3) + 1);
246 const char *pllsrc = pllcfgr & BIT(22) ? hse_clk : hsi_clk;
247 unsigned long pllq = (pllcfgr >> 24) & 0xf;
248
249 clk_register_fixed_factor(NULL, "vco", pllsrc, 0, plln, pllm);
250 clk_register_fixed_factor(NULL, "pll", "vco", 0, 1, pllp);
251 clk_register_fixed_factor(NULL, "pll48", "vco", 0, 1, pllq);
252}
253
254/*
255 * Converts the primary and secondary indices (as they appear in DT) to an
256 * offset into our struct clock array.
257 */
258static int stm32f4_rcc_lookup_clk_idx(u8 primary, u8 secondary)
259{
260 u64 table[ARRAY_SIZE(stm32f42xx_gate_map)];
261
262 if (primary == 1) {
263 if (WARN_ON(secondary > FCLK))
264 return -EINVAL;
265 return secondary;
266 }
267
268 memcpy(table, stm32f42xx_gate_map, sizeof(table));
269
270 /* only bits set in table can be used as indices */
271 if (WARN_ON(secondary > 8 * sizeof(table) ||
272 0 == (table[BIT_ULL_WORD(secondary)] &
273 BIT_ULL_MASK(secondary))))
274 return -EINVAL;
275
276 /* mask out bits above our current index */
277 table[BIT_ULL_WORD(secondary)] &=
278 GENMASK_ULL(secondary % BITS_PER_LONG_LONG, 0);
279
280 return FCLK + hweight64(table[0]) +
281 (BIT_ULL_WORD(secondary) >= 1 ? hweight64(table[1]) : 0) +
282 (BIT_ULL_WORD(secondary) >= 2 ? hweight64(table[2]) : 0);
283}
284
285static struct clk *
286stm32f4_rcc_lookup_clk(struct of_phandle_args *clkspec, void *data)
287{
288 int i = stm32f4_rcc_lookup_clk_idx(clkspec->args[0], clkspec->args[1]);
289
290 if (i < 0)
291 return ERR_PTR(-EINVAL);
292
293 return clks[i];
294}
295
296static const char *sys_parents[] __initdata = { "hsi", NULL, "pll" };
297
298static const struct clk_div_table ahb_div_table[] = {
299 { 0x0, 1 }, { 0x1, 1 }, { 0x2, 1 }, { 0x3, 1 },
300 { 0x4, 1 }, { 0x5, 1 }, { 0x6, 1 }, { 0x7, 1 },
301 { 0x8, 2 }, { 0x9, 4 }, { 0xa, 8 }, { 0xb, 16 },
302 { 0xc, 64 }, { 0xd, 128 }, { 0xe, 256 }, { 0xf, 512 },
303 { 0 },
304};
305
306static const struct clk_div_table apb_div_table[] = {
307 { 0, 1 }, { 0, 1 }, { 0, 1 }, { 0, 1 },
308 { 4, 2 }, { 5, 4 }, { 6, 8 }, { 7, 16 },
309 { 0 },
310};
311
312static void __init stm32f4_rcc_init(struct device_node *np)
313{
314 const char *hse_clk;
315 int n;
316
317 base = of_iomap(np, 0);
318 if (!base) {
319 pr_err("%s: unable to map resource", np->name);
320 return;
321 }
322
323 hse_clk = of_clk_get_parent_name(np, 0);
324
325 clk_register_fixed_rate_with_accuracy(NULL, "hsi", NULL, 0,
326 16000000, 160000);
327 stm32f4_rcc_register_pll(hse_clk, "hsi");
328
329 sys_parents[1] = hse_clk;
330 clk_register_mux_table(
331 NULL, "sys", sys_parents, ARRAY_SIZE(sys_parents), 0,
332 base + STM32F4_RCC_CFGR, 0, 3, 0, NULL, &stm32f4_clk_lock);
333
334 clk_register_divider_table(NULL, "ahb_div", "sys",
335 CLK_SET_RATE_PARENT, base + STM32F4_RCC_CFGR,
336 4, 4, 0, ahb_div_table, &stm32f4_clk_lock);
337
338 clk_register_divider_table(NULL, "apb1_div", "ahb_div",
339 CLK_SET_RATE_PARENT, base + STM32F4_RCC_CFGR,
340 10, 3, 0, apb_div_table, &stm32f4_clk_lock);
341 clk_register_apb_mul(NULL, "apb1_mul", "apb1_div",
342 CLK_SET_RATE_PARENT, 12);
343
344 clk_register_divider_table(NULL, "apb2_div", "ahb_div",
345 CLK_SET_RATE_PARENT, base + STM32F4_RCC_CFGR,
346 13, 3, 0, apb_div_table, &stm32f4_clk_lock);
347 clk_register_apb_mul(NULL, "apb2_mul", "apb2_div",
348 CLK_SET_RATE_PARENT, 15);
349
350 clks[SYSTICK] = clk_register_fixed_factor(NULL, "systick", "ahb_div",
351 0, 1, 8);
352 clks[FCLK] = clk_register_fixed_factor(NULL, "fclk", "ahb_div",
353 0, 1, 1);
354
355 for (n = 0; n < ARRAY_SIZE(stm32f4_gates); n++) {
356 const struct stm32f4_gate_data *gd = &stm32f4_gates[n];
357 unsigned int secondary =
358 8 * (gd->offset - STM32F4_RCC_AHB1ENR) + gd->bit_idx;
359 int idx = stm32f4_rcc_lookup_clk_idx(0, secondary);
360
361 if (idx < 0)
362 goto fail;
363
364 clks[idx] = clk_register_gate(
365 NULL, gd->name, gd->parent_name, gd->flags,
366 base + gd->offset, gd->bit_idx, 0, &stm32f4_clk_lock);
367
368 if (IS_ERR(clks[n])) {
369 pr_err("%s: Unable to register leaf clock %s\n",
370 np->full_name, gd->name);
371 goto fail;
372 }
373 }
374
375 of_clk_add_provider(np, stm32f4_rcc_lookup_clk, NULL);
376 return;
377fail:
378 iounmap(base);
379}
380CLK_OF_DECLARE(stm32f4_rcc, "st,stm32f42xx-rcc", stm32f4_rcc_init);