aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/clk/clk-nomadik.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/clk/clk-nomadik.c')
-rw-r--r--drivers/clk/clk-nomadik.c576
1 files changed, 547 insertions, 29 deletions
diff --git a/drivers/clk/clk-nomadik.c b/drivers/clk/clk-nomadik.c
index 6b4c70f7d23d..6d819a37f647 100644
--- a/drivers/clk/clk-nomadik.c
+++ b/drivers/clk/clk-nomadik.c
@@ -1,48 +1,566 @@
1/*
2 * Nomadik clock implementation
3 * Copyright (C) 2013 ST-Ericsson AB
4 * License terms: GNU General Public License (GPL) version 2
5 * Author: Linus Walleij <linus.walleij@linaro.org>
6 */
7
8#define pr_fmt(fmt) "Nomadik SRC clocks: " fmt
9
10#include <linux/bitops.h>
1#include <linux/clk.h> 11#include <linux/clk.h>
2#include <linux/clkdev.h> 12#include <linux/clkdev.h>
3#include <linux/err.h> 13#include <linux/err.h>
4#include <linux/io.h> 14#include <linux/io.h>
5#include <linux/clk-provider.h> 15#include <linux/clk-provider.h>
16#include <linux/of.h>
17#include <linux/of_address.h>
18#include <linux/debugfs.h>
19#include <linux/seq_file.h>
20#include <linux/spinlock.h>
21#include <linux/reboot.h>
6 22
7/* 23/*
8 * The Nomadik clock tree is described in the STN8815A12 DB V4.2 24 * The Nomadik clock tree is described in the STN8815A12 DB V4.2
9 * reference manual for the chip, page 94 ff. 25 * reference manual for the chip, page 94 ff.
26 * Clock IDs are in the STn8815 Reference Manual table 3, page 27.
10 */ 27 */
11 28
12void __init nomadik_clk_init(void) 29#define SRC_CR 0x00U
30#define SRC_XTALCR 0x0CU
31#define SRC_XTALCR_XTALTIMEN BIT(20)
32#define SRC_XTALCR_SXTALDIS BIT(19)
33#define SRC_XTALCR_MXTALSTAT BIT(2)
34#define SRC_XTALCR_MXTALEN BIT(1)
35#define SRC_XTALCR_MXTALOVER BIT(0)
36#define SRC_PLLCR 0x10U
37#define SRC_PLLCR_PLLTIMEN BIT(29)
38#define SRC_PLLCR_PLL2EN BIT(28)
39#define SRC_PLLCR_PLL1STAT BIT(2)
40#define SRC_PLLCR_PLL1EN BIT(1)
41#define SRC_PLLCR_PLL1OVER BIT(0)
42#define SRC_PLLFR 0x14U
43#define SRC_PCKEN0 0x24U
44#define SRC_PCKDIS0 0x28U
45#define SRC_PCKENSR0 0x2CU
46#define SRC_PCKSR0 0x30U
47#define SRC_PCKEN1 0x34U
48#define SRC_PCKDIS1 0x38U
49#define SRC_PCKENSR1 0x3CU
50#define SRC_PCKSR1 0x40U
51
52/* Lock protecting the SRC_CR register */
53static DEFINE_SPINLOCK(src_lock);
54/* Base address of the SRC */
55static void __iomem *src_base;
56
57/**
58 * struct clk_pll1 - Nomadik PLL1 clock
59 * @hw: corresponding clock hardware entry
60 * @id: PLL instance: 1 or 2
61 */
62struct clk_pll {
63 struct clk_hw hw;
64 int id;
65};
66
67/**
68 * struct clk_src - Nomadik src clock
69 * @hw: corresponding clock hardware entry
70 * @id: the clock ID
71 * @group1: true if the clock is in group1, else it is in group0
72 * @clkbit: bit 0...31 corresponding to the clock in each clock register
73 */
74struct clk_src {
75 struct clk_hw hw;
76 int id;
77 bool group1;
78 u32 clkbit;
79};
80
81#define to_pll(_hw) container_of(_hw, struct clk_pll, hw)
82#define to_src(_hw) container_of(_hw, struct clk_src, hw)
83
84static int pll_clk_enable(struct clk_hw *hw)
85{
86 struct clk_pll *pll = to_pll(hw);
87 u32 val;
88
89 spin_lock(&src_lock);
90 val = readl(src_base + SRC_PLLCR);
91 if (pll->id == 1) {
92 if (val & SRC_PLLCR_PLL1OVER) {
93 val |= SRC_PLLCR_PLL1EN;
94 writel(val, src_base + SRC_PLLCR);
95 }
96 } else if (pll->id == 2) {
97 val |= SRC_PLLCR_PLL2EN;
98 writel(val, src_base + SRC_PLLCR);
99 }
100 spin_unlock(&src_lock);
101 return 0;
102}
103
104static void pll_clk_disable(struct clk_hw *hw)
105{
106 struct clk_pll *pll = to_pll(hw);
107 u32 val;
108
109 spin_lock(&src_lock);
110 val = readl(src_base + SRC_PLLCR);
111 if (pll->id == 1) {
112 if (val & SRC_PLLCR_PLL1OVER) {
113 val &= ~SRC_PLLCR_PLL1EN;
114 writel(val, src_base + SRC_PLLCR);
115 }
116 } else if (pll->id == 2) {
117 val &= ~SRC_PLLCR_PLL2EN;
118 writel(val, src_base + SRC_PLLCR);
119 }
120 spin_unlock(&src_lock);
121}
122
123static int pll_clk_is_enabled(struct clk_hw *hw)
124{
125 struct clk_pll *pll = to_pll(hw);
126 u32 val;
127
128 val = readl(src_base + SRC_PLLCR);
129 if (pll->id == 1) {
130 if (val & SRC_PLLCR_PLL1OVER)
131 return !!(val & SRC_PLLCR_PLL1EN);
132 } else if (pll->id == 2) {
133 return !!(val & SRC_PLLCR_PLL2EN);
134 }
135 return 1;
136}
137
138static unsigned long pll_clk_recalc_rate(struct clk_hw *hw,
139 unsigned long parent_rate)
140{
141 struct clk_pll *pll = to_pll(hw);
142 u32 val;
143
144 val = readl(src_base + SRC_PLLFR);
145
146 if (pll->id == 1) {
147 u8 mul;
148 u8 div;
149
150 mul = (val >> 8) & 0x3FU;
151 mul += 2;
152 div = val & 0x07U;
153 return (parent_rate * mul) >> div;
154 }
155
156 if (pll->id == 2) {
157 u8 mul;
158
159 mul = (val >> 24) & 0x3FU;
160 mul += 2;
161 return (parent_rate * mul);
162 }
163
164 /* Unknown PLL */
165 return 0;
166}
167
168
169static const struct clk_ops pll_clk_ops = {
170 .enable = pll_clk_enable,
171 .disable = pll_clk_disable,
172 .is_enabled = pll_clk_is_enabled,
173 .recalc_rate = pll_clk_recalc_rate,
174};
175
176static struct clk * __init
177pll_clk_register(struct device *dev, const char *name,
178 const char *parent_name, u32 id)
13{ 179{
14 struct clk *clk; 180 struct clk *clk;
181 struct clk_pll *pll;
182 struct clk_init_data init;
15 183
16 clk = clk_register_fixed_rate(NULL, "apb_pclk", NULL, CLK_IS_ROOT, 0); 184 if (id != 1 && id != 2) {
17 clk_register_clkdev(clk, "apb_pclk", NULL); 185 pr_err("%s: the Nomadik has only PLL 1 & 2\n", __func__);
18 clk_register_clkdev(clk, NULL, "gpio.0"); 186 return ERR_PTR(-EINVAL);
19 clk_register_clkdev(clk, NULL, "gpio.1"); 187 }
20 clk_register_clkdev(clk, NULL, "gpio.2");
21 clk_register_clkdev(clk, NULL, "gpio.3");
22 clk_register_clkdev(clk, NULL, "rng");
23 clk_register_clkdev(clk, NULL, "fsmc-nand");
24 188
25 /* 189 pll = kzalloc(sizeof(*pll), GFP_KERNEL);
26 * The 2.4 MHz TIMCLK reference clock is active at boot time, this is 190 if (!pll) {
27 * actually the MXTALCLK @19.2 MHz divided by 8. This clock is used 191 pr_err("%s: could not allocate PLL clk\n", __func__);
28 * by the timers and watchdog. See page 105 ff. 192 return ERR_PTR(-ENOMEM);
29 */ 193 }
30 clk = clk_register_fixed_rate(NULL, "TIMCLK", NULL, CLK_IS_ROOT, 194
31 2400000); 195 init.name = name;
32 clk_register_clkdev(clk, NULL, "mtu0"); 196 init.ops = &pll_clk_ops;
33 clk_register_clkdev(clk, NULL, "mtu1"); 197 init.parent_names = (parent_name ? &parent_name : NULL);
198 init.num_parents = (parent_name ? 1 : 0);
199 pll->hw.init = &init;
200 pll->id = id;
201
202 pr_debug("register PLL1 clock \"%s\"\n", name);
203
204 clk = clk_register(dev, &pll->hw);
205 if (IS_ERR(clk))
206 kfree(pll);
207
208 return clk;
209}
210
211/*
212 * The Nomadik SRC clocks are gated, but not in the sense that
213 * you read-modify-write a register. Instead there are separate
214 * clock enable and clock disable registers. Writing a '1' bit in
215 * the enable register for a certain clock ungates that clock without
216 * affecting the other clocks. The disable register works the opposite
217 * way.
218 */
219
220static int src_clk_enable(struct clk_hw *hw)
221{
222 struct clk_src *sclk = to_src(hw);
223 u32 enreg = sclk->group1 ? SRC_PCKEN1 : SRC_PCKEN0;
224 u32 sreg = sclk->group1 ? SRC_PCKSR1 : SRC_PCKSR0;
225
226 writel(sclk->clkbit, src_base + enreg);
227 /* spin until enabled */
228 while (!(readl(src_base + sreg) & sclk->clkbit))
229 cpu_relax();
230 return 0;
231}
232
233static void src_clk_disable(struct clk_hw *hw)
234{
235 struct clk_src *sclk = to_src(hw);
236 u32 disreg = sclk->group1 ? SRC_PCKDIS1 : SRC_PCKDIS0;
237 u32 sreg = sclk->group1 ? SRC_PCKSR1 : SRC_PCKSR0;
238
239 writel(sclk->clkbit, src_base + disreg);
240 /* spin until disabled */
241 while (readl(src_base + sreg) & sclk->clkbit)
242 cpu_relax();
243}
244
245static int src_clk_is_enabled(struct clk_hw *hw)
246{
247 struct clk_src *sclk = to_src(hw);
248 u32 sreg = sclk->group1 ? SRC_PCKSR1 : SRC_PCKSR0;
249 u32 val = readl(src_base + sreg);
34 250
251 return !!(val & sclk->clkbit);
252}
253
254static unsigned long
255src_clk_recalc_rate(struct clk_hw *hw,
256 unsigned long parent_rate)
257{
258 return parent_rate;
259}
260
261static const struct clk_ops src_clk_ops = {
262 .enable = src_clk_enable,
263 .disable = src_clk_disable,
264 .is_enabled = src_clk_is_enabled,
265 .recalc_rate = src_clk_recalc_rate,
266};
267
268static struct clk * __init
269src_clk_register(struct device *dev, const char *name,
270 const char *parent_name, u8 id)
271{
272 struct clk *clk;
273 struct clk_src *sclk;
274 struct clk_init_data init;
275
276 sclk = kzalloc(sizeof(*sclk), GFP_KERNEL);
277 if (!sclk) {
278 pr_err("could not allocate SRC clock %s\n",
279 name);
280 return ERR_PTR(-ENOMEM);
281 }
282 init.name = name;
283 init.ops = &src_clk_ops;
284 /* Do not force-disable the static SDRAM controller */
285 if (id == 2)
286 init.flags = CLK_IGNORE_UNUSED;
287 else
288 init.flags = 0;
289 init.parent_names = (parent_name ? &parent_name : NULL);
290 init.num_parents = (parent_name ? 1 : 0);
291 sclk->hw.init = &init;
292 sclk->id = id;
293 sclk->group1 = (id > 31);
294 sclk->clkbit = BIT(id & 0x1f);
295
296 pr_debug("register clock \"%s\" ID: %d group: %d bits: %08x\n",
297 name, id, sclk->group1, sclk->clkbit);
298
299 clk = clk_register(dev, &sclk->hw);
300 if (IS_ERR(clk))
301 kfree(sclk);
302
303 return clk;
304}
305
306#ifdef CONFIG_DEBUG_FS
307
308static u32 src_pcksr0_boot;
309static u32 src_pcksr1_boot;
310
311static const char * const src_clk_names[] = {
312 "HCLKDMA0 ",
313 "HCLKSMC ",
314 "HCLKSDRAM ",
315 "HCLKDMA1 ",
316 "HCLKCLCD ",
317 "PCLKIRDA ",
318 "PCLKSSP ",
319 "PCLKUART0 ",
320 "PCLKSDI ",
321 "PCLKI2C0 ",
322 "PCLKI2C1 ",
323 "PCLKUART1 ",
324 "PCLMSP0 ",
325 "HCLKUSB ",
326 "HCLKDIF ",
327 "HCLKSAA ",
328 "HCLKSVA ",
329 "PCLKHSI ",
330 "PCLKXTI ",
331 "PCLKUART2 ",
332 "PCLKMSP1 ",
333 "PCLKMSP2 ",
334 "PCLKOWM ",
335 "HCLKHPI ",
336 "PCLKSKE ",
337 "PCLKHSEM ",
338 "HCLK3D ",
339 "HCLKHASH ",
340 "HCLKCRYP ",
341 "PCLKMSHC ",
342 "HCLKUSBM ",
343 "HCLKRNG ",
344 "RESERVED ",
345 "RESERVED ",
346 "RESERVED ",
347 "RESERVED ",
348 "CLDCLK ",
349 "IRDACLK ",
350 "SSPICLK ",
351 "UART0CLK ",
352 "SDICLK ",
353 "I2C0CLK ",
354 "I2C1CLK ",
355 "UART1CLK ",
356 "MSPCLK0 ",
357 "USBCLK ",
358 "DIFCLK ",
359 "IPI2CCLK ",
360 "IPBMCCLK ",
361 "HSICLKRX ",
362 "HSICLKTX ",
363 "UART2CLK ",
364 "MSPCLK1 ",
365 "MSPCLK2 ",
366 "OWMCLK ",
367 "RESERVED ",
368 "SKECLK ",
369 "RESERVED ",
370 "3DCLK ",
371 "PCLKMSP3 ",
372 "MSPCLK3 ",
373 "MSHCCLK ",
374 "USBMCLK ",
375 "RNGCCLK ",
376};
377
378static int nomadik_src_clk_show(struct seq_file *s, void *what)
379{
380 int i;
381 u32 src_pcksr0 = readl(src_base + SRC_PCKSR0);
382 u32 src_pcksr1 = readl(src_base + SRC_PCKSR1);
383 u32 src_pckensr0 = readl(src_base + SRC_PCKENSR0);
384 u32 src_pckensr1 = readl(src_base + SRC_PCKENSR1);
385
386 seq_printf(s, "Clock: Boot: Now: Request: ASKED:\n");
387 for (i = 0; i < ARRAY_SIZE(src_clk_names); i++) {
388 u32 pcksrb = (i < 0x20) ? src_pcksr0_boot : src_pcksr1_boot;
389 u32 pcksr = (i < 0x20) ? src_pcksr0 : src_pcksr1;
390 u32 pckreq = (i < 0x20) ? src_pckensr0 : src_pckensr1;
391 u32 mask = BIT(i & 0x1f);
392
393 seq_printf(s, "%s %s %s %s\n",
394 src_clk_names[i],
395 (pcksrb & mask) ? "on " : "off",
396 (pcksr & mask) ? "on " : "off",
397 (pckreq & mask) ? "on " : "off");
398 }
399 return 0;
400}
401
402static int nomadik_src_clk_open(struct inode *inode, struct file *file)
403{
404 return single_open(file, nomadik_src_clk_show, NULL);
405}
406
407static const struct file_operations nomadik_src_clk_debugfs_ops = {
408 .open = nomadik_src_clk_open,
409 .read = seq_read,
410 .llseek = seq_lseek,
411 .release = single_release,
412};
413
414static int __init nomadik_src_clk_init_debugfs(void)
415{
416 src_pcksr0_boot = readl(src_base + SRC_PCKSR0);
417 src_pcksr1_boot = readl(src_base + SRC_PCKSR1);
418 debugfs_create_file("nomadik-src-clk", S_IFREG | S_IRUGO,
419 NULL, NULL, &nomadik_src_clk_debugfs_ops);
420 return 0;
421}
422
423module_init(nomadik_src_clk_init_debugfs);
424
425#endif
426
427static void __init of_nomadik_pll_setup(struct device_node *np)
428{
429 struct clk *clk = ERR_PTR(-EINVAL);
430 const char *clk_name = np->name;
431 const char *parent_name;
432 u32 pll_id;
433
434 if (of_property_read_u32(np, "pll-id", &pll_id)) {
435 pr_err("%s: PLL \"%s\" missing pll-id property\n",
436 __func__, clk_name);
437 return;
438 }
439 parent_name = of_clk_get_parent_name(np, 0);
440 clk = pll_clk_register(NULL, clk_name, parent_name, pll_id);
441 if (!IS_ERR(clk))
442 of_clk_add_provider(np, of_clk_src_simple_get, clk);
443}
444
445static void __init of_nomadik_hclk_setup(struct device_node *np)
446{
447 struct clk *clk = ERR_PTR(-EINVAL);
448 const char *clk_name = np->name;
449 const char *parent_name;
450
451 parent_name = of_clk_get_parent_name(np, 0);
35 /* 452 /*
36 * At boot time, PLL2 is set to generate a set of fixed clocks, 453 * The HCLK divides PLL1 with 1 (passthru), 2, 3 or 4.
37 * one of them is CLK48, the 48 MHz clock, routed to the UART, MMC/SD
38 * I2C, IrDA, USB and SSP blocks.
39 */ 454 */
40 clk = clk_register_fixed_rate(NULL, "CLK48", NULL, CLK_IS_ROOT, 455 clk = clk_register_divider(NULL, clk_name, parent_name,
41 48000000); 456 0, src_base + SRC_CR,
42 clk_register_clkdev(clk, NULL, "uart0"); 457 13, 2,
43 clk_register_clkdev(clk, NULL, "uart1"); 458 CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO,
44 clk_register_clkdev(clk, NULL, "mmci"); 459 &src_lock);
45 clk_register_clkdev(clk, NULL, "ssp"); 460 if (!IS_ERR(clk))
46 clk_register_clkdev(clk, NULL, "nmk-i2c.0"); 461 of_clk_add_provider(np, of_clk_src_simple_get, clk);
47 clk_register_clkdev(clk, NULL, "nmk-i2c.1"); 462}
463
464static void __init of_nomadik_src_clk_setup(struct device_node *np)
465{
466 struct clk *clk = ERR_PTR(-EINVAL);
467 const char *clk_name = np->name;
468 const char *parent_name;
469 u32 clk_id;
470
471 if (of_property_read_u32(np, "clock-id", &clk_id)) {
472 pr_err("%s: SRC clock \"%s\" missing clock-id property\n",
473 __func__, clk_name);
474 return;
475 }
476 parent_name = of_clk_get_parent_name(np, 0);
477 clk = src_clk_register(NULL, clk_name, parent_name, clk_id);
478 if (!IS_ERR(clk))
479 of_clk_add_provider(np, of_clk_src_simple_get, clk);
480}
481
482static const __initconst struct of_device_id nomadik_src_match[] = {
483 { .compatible = "stericsson,nomadik-src" },
484 { /* sentinel */ }
485};
486
487static const __initconst struct of_device_id nomadik_src_clk_match[] = {
488 {
489 .compatible = "fixed-clock",
490 .data = of_fixed_clk_setup,
491 },
492 {
493 .compatible = "fixed-factor-clock",
494 .data = of_fixed_factor_clk_setup,
495 },
496 {
497 .compatible = "st,nomadik-pll-clock",
498 .data = of_nomadik_pll_setup,
499 },
500 {
501 .compatible = "st,nomadik-hclk-clock",
502 .data = of_nomadik_hclk_setup,
503 },
504 {
505 .compatible = "st,nomadik-src-clock",
506 .data = of_nomadik_src_clk_setup,
507 },
508 { /* sentinel */ }
509};
510
511static int nomadik_clk_reboot_handler(struct notifier_block *this,
512 unsigned long code,
513 void *unused)
514{
515 u32 val;
516
517 /* The main chrystal need to be enabled for reboot to work */
518 val = readl(src_base + SRC_XTALCR);
519 val &= ~SRC_XTALCR_MXTALOVER;
520 val |= SRC_XTALCR_MXTALEN;
521 pr_crit("force-enabling MXTALO\n");
522 writel(val, src_base + SRC_XTALCR);
523 return NOTIFY_OK;
524}
525
526static struct notifier_block nomadik_clk_reboot_notifier = {
527 .notifier_call = nomadik_clk_reboot_handler,
528};
529
530void __init nomadik_clk_init(void)
531{
532 struct device_node *np;
533 u32 val;
534
535 np = of_find_matching_node(NULL, nomadik_src_match);
536 if (!np) {
537 pr_crit("no matching node for SRC, aborting clock init\n");
538 return;
539 }
540 src_base = of_iomap(np, 0);
541 if (!src_base) {
542 pr_err("%s: must have src parent node with REGS (%s)\n",
543 __func__, np->name);
544 return;
545 }
546 val = readl(src_base + SRC_XTALCR);
547 pr_info("SXTALO is %s\n",
548 (val & SRC_XTALCR_SXTALDIS) ? "disabled" : "enabled");
549 pr_info("MXTAL is %s\n",
550 (val & SRC_XTALCR_MXTALSTAT) ? "enabled" : "disabled");
551 if (of_property_read_bool(np, "disable-sxtalo")) {
552 /* The machine uses an external oscillator circuit */
553 val |= SRC_XTALCR_SXTALDIS;
554 pr_info("disabling SXTALO\n");
555 }
556 if (of_property_read_bool(np, "disable-mxtalo")) {
557 /* Disable this too: also run by external oscillator */
558 val |= SRC_XTALCR_MXTALOVER;
559 val &= ~SRC_XTALCR_MXTALEN;
560 pr_info("disabling MXTALO\n");
561 }
562 writel(val, src_base + SRC_XTALCR);
563 register_reboot_notifier(&nomadik_clk_reboot_notifier);
564
565 of_clk_init(nomadik_src_clk_match);
48} 566}