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