Commit | Line | Data |
---|---|---|
358bdf89 DT |
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 | ||
35 | struct 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 | ||
43 | static 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 | ||
129 | enum { 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 | */ | |
135 | static const u64 stm32f42xx_gate_map[] = { 0x000000f17ef417ffull, | |
136 | 0x0000000000000001ull, | |
137 | 0x04777f33f6fec9ffull }; | |
138 | ||
139 | static struct clk *clks[MAX_CLKS]; | |
140 | static DEFINE_SPINLOCK(stm32f4_clk_lock); | |
141 | static 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 | */ | |
151 | struct 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 | ||
158 | static 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 | ||
169 | static 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 | ||
188 | static 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 | ||
200 | static 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 | ||
206 | static 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 | */ | |
239 | static 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 | */ | |
258 | static 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 */ | |
15ab3827 | 271 | if (WARN_ON(secondary >= BITS_PER_BYTE * sizeof(table) || |
358bdf89 DT |
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 | ||
285 | static struct clk * | |
286 | stm32f4_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 | ||
296 | static const char *sys_parents[] __initdata = { "hsi", NULL, "pll" }; | |
297 | ||
298 | static 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 | ||
306 | static 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 | ||
312 | static 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; | |
377 | fail: | |
378 | iounmap(base); | |
379 | } | |
380 | CLK_OF_DECLARE(stm32f4_rcc, "st,stm32f42xx-rcc", stm32f4_rcc_init); |