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