aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Makefile1
-rw-r--r--arch/powerpc/platforms/512x/Kconfig1
-rw-r--r--arch/powerpc/platforms/512x/Makefile1
-rw-r--r--arch/powerpc/platforms/512x/clock.c729
4 files changed, 732 insertions, 0 deletions
diff --git a/Makefile b/Makefile
index 6aff5f47c21d..fc3ae9fc8471 100644
--- a/Makefile
+++ b/Makefile
@@ -1,3 +1,4 @@
1FRED=42
1VERSION = 2 2VERSION = 2
2PATCHLEVEL = 6 3PATCHLEVEL = 6
3SUBLEVEL = 26 4SUBLEVEL = 26
diff --git a/arch/powerpc/platforms/512x/Kconfig b/arch/powerpc/platforms/512x/Kconfig
index 4c0da0c079e9..162af067d128 100644
--- a/arch/powerpc/platforms/512x/Kconfig
+++ b/arch/powerpc/platforms/512x/Kconfig
@@ -2,6 +2,7 @@ config PPC_MPC512x
2 bool 2 bool
3 select FSL_SOC 3 select FSL_SOC
4 select IPIC 4 select IPIC
5 select PPC_CLOCK
5 default n 6 default n
6 7
7config PPC_MPC5121 8config PPC_MPC5121
diff --git a/arch/powerpc/platforms/512x/Makefile b/arch/powerpc/platforms/512x/Makefile
index 232c89f2039a..90910c1f725b 100644
--- a/arch/powerpc/platforms/512x/Makefile
+++ b/arch/powerpc/platforms/512x/Makefile
@@ -1,4 +1,5 @@
1# 1#
2# Makefile for the Freescale PowerPC 512x linux kernel. 2# Makefile for the Freescale PowerPC 512x linux kernel.
3# 3#
4obj-y += clock.o
4obj-$(CONFIG_MPC5121_ADS) += mpc5121_ads.o 5obj-$(CONFIG_MPC5121_ADS) += mpc5121_ads.o
diff --git a/arch/powerpc/platforms/512x/clock.c b/arch/powerpc/platforms/512x/clock.c
new file mode 100644
index 000000000000..f416014ee727
--- /dev/null
+++ b/arch/powerpc/platforms/512x/clock.c
@@ -0,0 +1,729 @@
1/*
2 * Copyright (C) 2007,2008 Freescale Semiconductor, Inc. All rights reserved.
3 *
4 * Author: John Rigby <jrigby@freescale.com>
5 *
6 * Implements the clk api defined in include/linux/clk.h
7 *
8 * Original based on linux/arch/arm/mach-integrator/clock.c
9 *
10 * Copyright (C) 2004 ARM Limited.
11 * Written by Deep Blue Solutions Limited.
12 *
13 * This program is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License version 2 as
15 * published by the Free Software Foundation.
16 */
17#include <linux/kernel.h>
18#include <linux/list.h>
19#include <linux/errno.h>
20#include <linux/err.h>
21#include <linux/string.h>
22#include <linux/clk.h>
23#include <linux/mutex.h>
24#include <linux/io.h>
25
26#include <linux/of_platform.h>
27#include <asm/mpc512x.h>
28#include <asm/clk_interface.h>
29
30#undef CLK_DEBUG
31
32static int clocks_initialized;
33
34#define CLK_HAS_RATE 0x1 /* has rate in MHz */
35#define CLK_HAS_CTRL 0x2 /* has control reg and bit */
36
37struct clk {
38 struct list_head node;
39 char name[32];
40 int flags;
41 struct device *dev;
42 unsigned long rate;
43 struct module *owner;
44 void (*calc) (struct clk *);
45 struct clk *parent;
46 int reg, bit; /* CLK_HAS_CTRL */
47 int div_shift; /* only used by generic_div_clk_calc */
48};
49
50static LIST_HEAD(clocks);
51static DEFINE_MUTEX(clocks_mutex);
52
53static struct clk *mpc5121_clk_get(struct device *dev, const char *id)
54{
55 struct clk *p, *clk = ERR_PTR(-ENOENT);
56 int dev_match = 0;
57 int id_match = 0;
58
59 if (dev == NULL && id == NULL)
60 return NULL;
61
62 mutex_lock(&clocks_mutex);
63 list_for_each_entry(p, &clocks, node) {
64 if (dev && dev == p->dev)
65 dev_match++;
66 if (strcmp(id, p->name) == 0)
67 id_match++;
68 if ((dev_match || id_match) && try_module_get(p->owner)) {
69 clk = p;
70 break;
71 }
72 }
73 mutex_unlock(&clocks_mutex);
74
75 return clk;
76}
77
78#ifdef CLK_DEBUG
79static void dump_clocks(void)
80{
81 struct clk *p;
82
83 mutex_lock(&clocks_mutex);
84 printk(KERN_INFO "CLOCKS:\n");
85 list_for_each_entry(p, &clocks, node) {
86 printk(KERN_INFO " %s %ld", p->name, p->rate);
87 if (p->parent)
88 printk(KERN_INFO " %s %ld", p->parent->name,
89 p->parent->rate);
90 if (p->flags & CLK_HAS_CTRL)
91 printk(KERN_INFO " reg/bit %d/%d", p->reg, p->bit);
92 printk("\n");
93 }
94 mutex_unlock(&clocks_mutex);
95}
96#define DEBUG_CLK_DUMP() dump_clocks()
97#else
98#define DEBUG_CLK_DUMP()
99#endif
100
101
102static void mpc5121_clk_put(struct clk *clk)
103{
104 module_put(clk->owner);
105}
106
107#define NRPSC 12
108
109struct mpc512x_clockctl {
110 u32 spmr; /* System PLL Mode Reg */
111 u32 sccr[2]; /* System Clk Ctrl Reg 1 & 2 */
112 u32 scfr1; /* System Clk Freq Reg 1 */
113 u32 scfr2; /* System Clk Freq Reg 2 */
114 u32 reserved;
115 u32 bcr; /* Bread Crumb Reg */
116 u32 pccr[NRPSC]; /* PSC Clk Ctrl Reg 0-11 */
117 u32 spccr; /* SPDIF Clk Ctrl Reg */
118 u32 cccr; /* CFM Clk Ctrl Reg */
119 u32 dccr; /* DIU Clk Cnfg Reg */
120};
121
122struct mpc512x_clockctl __iomem *clockctl;
123
124static int mpc5121_clk_enable(struct clk *clk)
125{
126 unsigned int mask;
127
128 if (clk->flags & CLK_HAS_CTRL) {
129 mask = in_be32(&clockctl->sccr[clk->reg]);
130 mask |= 1 << clk->bit;
131 out_be32(&clockctl->sccr[clk->reg], mask);
132 }
133 return 0;
134}
135
136static void mpc5121_clk_disable(struct clk *clk)
137{
138 unsigned int mask;
139
140 if (clk->flags & CLK_HAS_CTRL) {
141 mask = in_be32(&clockctl->sccr[clk->reg]);
142 mask &= ~(1 << clk->bit);
143 out_be32(&clockctl->sccr[clk->reg], mask);
144 }
145}
146
147static unsigned long mpc5121_clk_get_rate(struct clk *clk)
148{
149 if (clk->flags & CLK_HAS_RATE)
150 return clk->rate;
151 else
152 return 0;
153}
154
155static long mpc5121_clk_round_rate(struct clk *clk, unsigned long rate)
156{
157 return rate;
158}
159
160static int mpc5121_clk_set_rate(struct clk *clk, unsigned long rate)
161{
162 return 0;
163}
164
165static int clk_register(struct clk *clk)
166{
167 mutex_lock(&clocks_mutex);
168 list_add(&clk->node, &clocks);
169 mutex_unlock(&clocks_mutex);
170 return 0;
171}
172
173static unsigned long spmf_mult(void)
174{
175 /*
176 * Convert spmf to multiplier
177 */
178 static int spmf_to_mult[] = {
179 68, 1, 12, 16,
180 20, 24, 28, 32,
181 36, 40, 44, 48,
182 52, 56, 60, 64
183 };
184 int spmf = (clockctl->spmr >> 24) & 0xf;
185 return spmf_to_mult[spmf];
186}
187
188static unsigned long sysdiv_div_x_2(void)
189{
190 /*
191 * Convert sysdiv to divisor x 2
192 * Some divisors have fractional parts so
193 * multiply by 2 then divide by this value
194 */
195 static int sysdiv_to_div_x_2[] = {
196 4, 5, 6, 7,
197 8, 9, 10, 14,
198 12, 16, 18, 22,
199 20, 24, 26, 30,
200 28, 32, 34, 38,
201 36, 40, 42, 46,
202 44, 48, 50, 54,
203 52, 56, 58, 62,
204 60, 64, 66,
205 };
206 int sysdiv = (clockctl->scfr2 >> 26) & 0x3f;
207 return sysdiv_to_div_x_2[sysdiv];
208}
209
210static unsigned long ref_to_sys(unsigned long rate)
211{
212 rate *= spmf_mult();
213 rate *= 2;
214 rate /= sysdiv_div_x_2();
215
216 return rate;
217}
218
219static unsigned long sys_to_ref(unsigned long rate)
220{
221 rate *= sysdiv_div_x_2();
222 rate /= 2;
223 rate /= spmf_mult();
224
225 return rate;
226}
227
228static long ips_to_ref(unsigned long rate)
229{
230 int ips_div = (clockctl->scfr1 >> 23) & 0x7;
231
232 rate *= ips_div; /* csb_clk = ips_clk * ips_div */
233 rate *= 2; /* sys_clk = csb_clk * 2 */
234 return sys_to_ref(rate);
235}
236
237static unsigned long devtree_getfreq(char *clockname)
238{
239 struct device_node *np;
240 const unsigned int *prop;
241 unsigned int val = 0;
242
243 np = of_find_compatible_node(NULL, NULL, "fsl,mpc5121-immr");
244 if (np) {
245 prop = of_get_property(np, clockname, NULL);
246 if (prop)
247 val = *prop;
248 of_node_put(np);
249 }
250 return val;
251}
252
253static void ref_clk_calc(struct clk *clk)
254{
255 unsigned long rate;
256
257 rate = devtree_getfreq("bus-frequency");
258 if (rate == 0) {
259 printk(KERN_ERR "No bus-frequency in dev tree\n");
260 clk->rate = 0;
261 return;
262 }
263 clk->rate = ips_to_ref(rate);
264}
265
266static struct clk ref_clk = {
267 .name = "ref_clk",
268 .calc = ref_clk_calc,
269};
270
271
272static void sys_clk_calc(struct clk *clk)
273{
274 clk->rate = ref_to_sys(ref_clk.rate);
275}
276
277static struct clk sys_clk = {
278 .name = "sys_clk",
279 .calc = sys_clk_calc,
280};
281
282static void diu_clk_calc(struct clk *clk)
283{
284 int diudiv_x_2 = clockctl->scfr1 & 0xff;
285 unsigned long rate;
286
287 rate = sys_clk.rate;
288
289 rate *= 2;
290 rate /= diudiv_x_2;
291
292 clk->rate = rate;
293}
294
295static void half_clk_calc(struct clk *clk)
296{
297 clk->rate = clk->parent->rate / 2;
298}
299
300static void generic_div_clk_calc(struct clk *clk)
301{
302 int div = (clockctl->scfr1 >> clk->div_shift) & 0x7;
303
304 clk->rate = clk->parent->rate / div;
305}
306
307static void unity_clk_calc(struct clk *clk)
308{
309 clk->rate = clk->parent->rate;
310}
311
312static struct clk csb_clk = {
313 .name = "csb_clk",
314 .calc = half_clk_calc,
315 .parent = &sys_clk,
316};
317
318static void e300_clk_calc(struct clk *clk)
319{
320 int spmf = (clockctl->spmr >> 16) & 0xf;
321 int ratex2 = clk->parent->rate * spmf;
322
323 clk->rate = ratex2 / 2;
324}
325
326static struct clk e300_clk = {
327 .name = "e300_clk",
328 .calc = e300_clk_calc,
329 .parent = &csb_clk,
330};
331
332static struct clk ips_clk = {
333 .name = "ips_clk",
334 .calc = generic_div_clk_calc,
335 .parent = &csb_clk,
336 .div_shift = 23,
337};
338
339/*
340 * Clocks controlled by SCCR1 (.reg = 0)
341 */
342static struct clk lpc_clk = {
343 .name = "lpc_clk",
344 .flags = CLK_HAS_CTRL,
345 .reg = 0,
346 .bit = 30,
347 .calc = generic_div_clk_calc,
348 .parent = &ips_clk,
349 .div_shift = 11,
350};
351
352static struct clk nfc_clk = {
353 .name = "nfc_clk",
354 .flags = CLK_HAS_CTRL,
355 .reg = 0,
356 .bit = 29,
357 .calc = generic_div_clk_calc,
358 .parent = &ips_clk,
359 .div_shift = 8,
360};
361
362static struct clk pata_clk = {
363 .name = "pata_clk",
364 .flags = CLK_HAS_CTRL,
365 .reg = 0,
366 .bit = 28,
367 .calc = unity_clk_calc,
368 .parent = &ips_clk,
369};
370
371/*
372 * PSC clocks (bits 27 - 16)
373 * are setup elsewhere
374 */
375
376static struct clk sata_clk = {
377 .name = "sata_clk",
378 .flags = CLK_HAS_CTRL,
379 .reg = 0,
380 .bit = 14,
381 .calc = unity_clk_calc,
382 .parent = &ips_clk,
383};
384
385static struct clk fec_clk = {
386 .name = "fec_clk",
387 .flags = CLK_HAS_CTRL,
388 .reg = 0,
389 .bit = 13,
390 .calc = unity_clk_calc,
391 .parent = &ips_clk,
392};
393
394static struct clk pci_clk = {
395 .name = "pci_clk",
396 .flags = CLK_HAS_CTRL,
397 .reg = 0,
398 .bit = 11,
399 .calc = generic_div_clk_calc,
400 .parent = &csb_clk,
401 .div_shift = 20,
402};
403
404/*
405 * Clocks controlled by SCCR2 (.reg = 1)
406 */
407static struct clk diu_clk = {
408 .name = "diu_clk",
409 .flags = CLK_HAS_CTRL,
410 .reg = 1,
411 .bit = 31,
412 .calc = diu_clk_calc,
413};
414
415static struct clk axe_clk = {
416 .name = "axe_clk",
417 .flags = CLK_HAS_CTRL,
418 .reg = 1,
419 .bit = 30,
420 .calc = unity_clk_calc,
421 .parent = &csb_clk,
422};
423
424static struct clk usb1_clk = {
425 .name = "usb1_clk",
426 .flags = CLK_HAS_CTRL,
427 .reg = 1,
428 .bit = 28,
429 .calc = unity_clk_calc,
430 .parent = &csb_clk,
431};
432
433static struct clk usb2_clk = {
434 .name = "usb2_clk",
435 .flags = CLK_HAS_CTRL,
436 .reg = 1,
437 .bit = 27,
438 .calc = unity_clk_calc,
439 .parent = &csb_clk,
440};
441
442static struct clk i2c_clk = {
443 .name = "i2c_clk",
444 .flags = CLK_HAS_CTRL,
445 .reg = 1,
446 .bit = 26,
447 .calc = unity_clk_calc,
448 .parent = &ips_clk,
449};
450
451static struct clk mscan_clk = {
452 .name = "mscan_clk",
453 .flags = CLK_HAS_CTRL,
454 .reg = 1,
455 .bit = 25,
456 .calc = unity_clk_calc,
457 .parent = &ips_clk,
458};
459
460static struct clk sdhc_clk = {
461 .name = "sdhc_clk",
462 .flags = CLK_HAS_CTRL,
463 .reg = 1,
464 .bit = 24,
465 .calc = unity_clk_calc,
466 .parent = &ips_clk,
467};
468
469static struct clk mbx_bus_clk = {
470 .name = "mbx_bus_clk",
471 .flags = CLK_HAS_CTRL,
472 .reg = 1,
473 .bit = 22,
474 .calc = half_clk_calc,
475 .parent = &csb_clk,
476};
477
478static struct clk mbx_clk = {
479 .name = "mbx_clk",
480 .flags = CLK_HAS_CTRL,
481 .reg = 1,
482 .bit = 21,
483 .calc = unity_clk_calc,
484 .parent = &csb_clk,
485};
486
487static struct clk mbx_3d_clk = {
488 .name = "mbx_3d_clk",
489 .flags = CLK_HAS_CTRL,
490 .reg = 1,
491 .bit = 20,
492 .calc = generic_div_clk_calc,
493 .parent = &mbx_bus_clk,
494 .div_shift = 14,
495};
496
497static void psc_mclk_in_calc(struct clk *clk)
498{
499 clk->rate = devtree_getfreq("psc_mclk_in");
500 if (!clk->rate)
501 clk->rate = 25000000;
502}
503
504static struct clk psc_mclk_in = {
505 .name = "psc_mclk_in",
506 .calc = psc_mclk_in_calc,
507};
508
509static struct clk spdif_txclk = {
510 .name = "spdif_txclk",
511 .flags = CLK_HAS_CTRL,
512 .reg = 1,
513 .bit = 23,
514};
515
516static struct clk spdif_rxclk = {
517 .name = "spdif_rxclk",
518 .flags = CLK_HAS_CTRL,
519 .reg = 1,
520 .bit = 23,
521};
522
523static void ac97_clk_calc(struct clk *clk)
524{
525 /* ac97 bit clock is always 24.567 MHz */
526 clk->rate = 24567000;
527}
528
529static struct clk ac97_clk = {
530 .name = "ac97_clk_in",
531 .calc = ac97_clk_calc,
532};
533
534struct clk *rate_clks[] = {
535 &ref_clk,
536 &sys_clk,
537 &diu_clk,
538 &csb_clk,
539 &e300_clk,
540 &ips_clk,
541 &fec_clk,
542 &sata_clk,
543 &pata_clk,
544 &nfc_clk,
545 &lpc_clk,
546 &mbx_bus_clk,
547 &mbx_clk,
548 &mbx_3d_clk,
549 &axe_clk,
550 &usb1_clk,
551 &usb2_clk,
552 &i2c_clk,
553 &mscan_clk,
554 &sdhc_clk,
555 &pci_clk,
556 &psc_mclk_in,
557 &spdif_txclk,
558 &spdif_rxclk,
559 &ac97_clk,
560 NULL
561};
562
563static void rate_clk_init(struct clk *clk)
564{
565 if (clk->calc) {
566 clk->calc(clk);
567 clk->flags |= CLK_HAS_RATE;
568 clk_register(clk);
569 } else {
570 printk(KERN_WARNING
571 "Could not initialize clk %s without a calc routine\n",
572 clk->name);
573 }
574}
575
576static void rate_clks_init(void)
577{
578 struct clk **cpp, *clk;
579
580 cpp = rate_clks;
581 while ((clk = *cpp++))
582 rate_clk_init(clk);
583}
584
585/*
586 * There are two clk enable registers with 32 enable bits each
587 * psc clocks and device clocks are all stored in dev_clks
588 */
589struct clk dev_clks[2][32];
590
591/*
592 * Given a psc number return the dev_clk
593 * associated with it
594 */
595static struct clk *psc_dev_clk(int pscnum)
596{
597 int reg, bit;
598 struct clk *clk;
599
600 reg = 0;
601 bit = 27 - pscnum;
602
603 clk = &dev_clks[reg][bit];
604 clk->reg = 0;
605 clk->bit = bit;
606 return clk;
607}
608
609/*
610 * PSC clock rate calculation
611 */
612static void psc_calc_rate(struct clk *clk, int pscnum, struct device_node *np)
613{
614 unsigned long mclk_src = sys_clk.rate;
615 unsigned long mclk_div;
616
617 /*
618 * Can only change value of mclk divider
619 * when the divider is disabled.
620 *
621 * Zero is not a valid divider so minimum
622 * divider is 1
623 *
624 * disable/set divider/enable
625 */
626 out_be32(&clockctl->pccr[pscnum], 0);
627 out_be32(&clockctl->pccr[pscnum], 0x00020000);
628 out_be32(&clockctl->pccr[pscnum], 0x00030000);
629
630 if (clockctl->pccr[pscnum] & 0x80) {
631 clk->rate = spdif_rxclk.rate;
632 return;
633 }
634
635 switch ((clockctl->pccr[pscnum] >> 14) & 0x3) {
636 case 0:
637 mclk_src = sys_clk.rate;
638 break;
639 case 1:
640 mclk_src = ref_clk.rate;
641 break;
642 case 2:
643 mclk_src = psc_mclk_in.rate;
644 break;
645 case 3:
646 mclk_src = spdif_txclk.rate;
647 break;
648 }
649
650 mclk_div = ((clockctl->pccr[pscnum] >> 17) & 0x7fff) + 1;
651 clk->rate = mclk_src / mclk_div;
652}
653
654/*
655 * Find all psc nodes in device tree and assign a clock
656 * with name "psc%d_mclk" and dev pointing at the device
657 * returned from of_find_device_by_node
658 */
659static void psc_clks_init(void)
660{
661 struct device_node *np;
662 const u32 *cell_index;
663 struct of_device *ofdev;
664
665 for_each_compatible_node(np, NULL, "fsl,mpc5121-psc") {
666 cell_index = of_get_property(np, "cell-index", NULL);
667 if (cell_index) {
668 int pscnum = *cell_index;
669 struct clk *clk = psc_dev_clk(pscnum);
670
671 clk->flags = CLK_HAS_RATE | CLK_HAS_CTRL;
672 ofdev = of_find_device_by_node(np);
673 clk->dev = &ofdev->dev;
674 /*
675 * AC97 is special rate clock does
676 * not go through normal path
677 */
678 if (strcmp("ac97", np->name) == 0)
679 clk->rate = ac97_clk.rate;
680 else
681 psc_calc_rate(clk, pscnum, np);
682 sprintf(clk->name, "psc%d_mclk", pscnum);
683 clk_register(clk);
684 clk_enable(clk);
685 }
686 }
687}
688
689static struct clk_interface mpc5121_clk_functions = {
690 .clk_get = mpc5121_clk_get,
691 .clk_enable = mpc5121_clk_enable,
692 .clk_disable = mpc5121_clk_disable,
693 .clk_get_rate = mpc5121_clk_get_rate,
694 .clk_put = mpc5121_clk_put,
695 .clk_round_rate = mpc5121_clk_round_rate,
696 .clk_set_rate = mpc5121_clk_set_rate,
697 .clk_set_parent = NULL,
698 .clk_get_parent = NULL,
699};
700
701static int
702mpc5121_clk_init(void)
703{
704 struct device_node *np;
705
706 np = of_find_compatible_node(NULL, NULL, "fsl,mpc5121-clock");
707 if (np) {
708 clockctl = of_iomap(np, 0);
709 of_node_put(np);
710 }
711
712 if (!clockctl) {
713 printk(KERN_ERR "Could not map clock control registers\n");
714 return 0;
715 }
716
717 rate_clks_init();
718 psc_clks_init();
719
720 /* leave clockctl mapped forever */
721 /*iounmap(clockctl); */
722 DEBUG_CLK_DUMP();
723 clocks_initialized++;
724 clk_functions = mpc5121_clk_functions;
725 return 0;
726}
727
728
729arch_initcall(mpc5121_clk_init);