aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
Diffstat (limited to 'arch')
-rw-r--r--arch/arm/mach-s3c64xx/Kconfig2
-rw-r--r--arch/arm/mach-s3c64xx/clock.c507
-rw-r--r--arch/arm/plat-s3c64xx/Kconfig12
-rw-r--r--arch/arm/plat-s3c64xx/Makefile3
-rw-r--r--arch/arm/plat-s3c64xx/s3c6400-clock.c536
5 files changed, 507 insertions, 553 deletions
diff --git a/arch/arm/mach-s3c64xx/Kconfig b/arch/arm/mach-s3c64xx/Kconfig
index 33d82b1c9eff..8c2c89c24fce 100644
--- a/arch/arm/mach-s3c64xx/Kconfig
+++ b/arch/arm/mach-s3c64xx/Kconfig
@@ -7,13 +7,11 @@
7 7
8config CPU_S3C6400 8config CPU_S3C6400
9 bool 9 bool
10 select CPU_S3C6400_CLOCK
11 help 10 help
12 Enable S3C6400 CPU support 11 Enable S3C6400 CPU support
13 12
14config CPU_S3C6410 13config CPU_S3C6410
15 bool 14 bool
16 select CPU_S3C6400_CLOCK
17 help 15 help
18 Enable S3C6410 CPU support 16 Enable S3C6410 CPU support
19 17
diff --git a/arch/arm/mach-s3c64xx/clock.c b/arch/arm/mach-s3c64xx/clock.c
index 229bb3bcc54f..9b587e267422 100644
--- a/arch/arm/mach-s3c64xx/clock.c
+++ b/arch/arm/mach-s3c64xx/clock.c
@@ -16,6 +16,8 @@
16#include <linux/module.h> 16#include <linux/module.h>
17#include <linux/interrupt.h> 17#include <linux/interrupt.h>
18#include <linux/ioport.h> 18#include <linux/ioport.h>
19#include <linux/clk.h>
20#include <linux/err.h>
19#include <linux/io.h> 21#include <linux/io.h>
20 22
21#include <mach/hardware.h> 23#include <mach/hardware.h>
@@ -27,7 +29,25 @@
27 29
28#include <plat/cpu.h> 30#include <plat/cpu.h>
29#include <plat/devs.h> 31#include <plat/devs.h>
32#include <plat/cpu-freq.h>
30#include <plat/clock.h> 33#include <plat/clock.h>
34#include <plat/clock-clksrc.h>
35
36/* fin_apll, fin_mpll and fin_epll are all the same clock, which we call
37 * ext_xtal_mux for want of an actual name from the manual.
38*/
39
40static struct clk clk_ext_xtal_mux = {
41 .name = "ext_xtal",
42 .id = -1,
43};
44
45#define clk_fin_apll clk_ext_xtal_mux
46#define clk_fin_mpll clk_ext_xtal_mux
47#define clk_fin_epll clk_ext_xtal_mux
48
49#define clk_fout_mpll clk_mpll
50#define clk_fout_epll clk_epll
31 51
32struct clk clk_h2 = { 52struct clk clk_h2 = {
33 .name = "hclk2", 53 .name = "hclk2",
@@ -273,6 +293,493 @@ static struct clk init_clocks[] = {
273 } 293 }
274}; 294};
275 295
296
297static struct clk clk_fout_apll = {
298 .name = "fout_apll",
299 .id = -1,
300};
301
302static struct clk *clk_src_apll_list[] = {
303 [0] = &clk_fin_apll,
304 [1] = &clk_fout_apll,
305};
306
307static struct clksrc_sources clk_src_apll = {
308 .sources = clk_src_apll_list,
309 .nr_sources = ARRAY_SIZE(clk_src_apll_list),
310};
311
312static struct clksrc_clk clk_mout_apll = {
313 .clk = {
314 .name = "mout_apll",
315 .id = -1,
316 },
317 .reg_src = { .reg = S3C_CLK_SRC, .shift = 0, .size = 1 },
318 .sources = &clk_src_apll,
319};
320
321static struct clk *clk_src_epll_list[] = {
322 [0] = &clk_fin_epll,
323 [1] = &clk_fout_epll,
324};
325
326static struct clksrc_sources clk_src_epll = {
327 .sources = clk_src_epll_list,
328 .nr_sources = ARRAY_SIZE(clk_src_epll_list),
329};
330
331static struct clksrc_clk clk_mout_epll = {
332 .clk = {
333 .name = "mout_epll",
334 .id = -1,
335 },
336 .reg_src = { .reg = S3C_CLK_SRC, .shift = 2, .size = 1 },
337 .sources = &clk_src_epll,
338};
339
340static struct clk *clk_src_mpll_list[] = {
341 [0] = &clk_fin_mpll,
342 [1] = &clk_fout_mpll,
343};
344
345static struct clksrc_sources clk_src_mpll = {
346 .sources = clk_src_mpll_list,
347 .nr_sources = ARRAY_SIZE(clk_src_mpll_list),
348};
349
350static struct clksrc_clk clk_mout_mpll = {
351 .clk = {
352 .name = "mout_mpll",
353 .id = -1,
354 },
355 .reg_src = { .reg = S3C_CLK_SRC, .shift = 1, .size = 1 },
356 .sources = &clk_src_mpll,
357};
358
359static unsigned int armclk_mask;
360
361static unsigned long s3c64xx_clk_arm_get_rate(struct clk *clk)
362{
363 unsigned long rate = clk_get_rate(clk->parent);
364 u32 clkdiv;
365
366 /* divisor mask starts at bit0, so no need to shift */
367 clkdiv = __raw_readl(S3C_CLK_DIV0) & armclk_mask;
368
369 return rate / (clkdiv + 1);
370}
371
372static unsigned long s3c64xx_clk_arm_round_rate(struct clk *clk,
373 unsigned long rate)
374{
375 unsigned long parent = clk_get_rate(clk->parent);
376 u32 div;
377
378 if (parent < rate)
379 return parent;
380
381 div = (parent / rate) - 1;
382 if (div > armclk_mask)
383 div = armclk_mask;
384
385 return parent / (div + 1);
386}
387
388static int s3c64xx_clk_arm_set_rate(struct clk *clk, unsigned long rate)
389{
390 unsigned long parent = clk_get_rate(clk->parent);
391 u32 div;
392 u32 val;
393
394 if (rate < parent / (armclk_mask + 1))
395 return -EINVAL;
396
397 rate = clk_round_rate(clk, rate);
398 div = clk_get_rate(clk->parent) / rate;
399
400 val = __raw_readl(S3C_CLK_DIV0);
401 val &= ~armclk_mask;
402 val |= (div - 1);
403 __raw_writel(val, S3C_CLK_DIV0);
404
405 return 0;
406
407}
408
409static struct clk clk_arm = {
410 .name = "armclk",
411 .id = -1,
412 .parent = &clk_mout_apll.clk,
413 .ops = &(struct clk_ops) {
414 .get_rate = s3c64xx_clk_arm_get_rate,
415 .set_rate = s3c64xx_clk_arm_set_rate,
416 .round_rate = s3c64xx_clk_arm_round_rate,
417 },
418};
419
420static unsigned long s3c64xx_clk_doutmpll_get_rate(struct clk *clk)
421{
422 unsigned long rate = clk_get_rate(clk->parent);
423
424 printk(KERN_DEBUG "%s: parent is %ld\n", __func__, rate);
425
426 if (__raw_readl(S3C_CLK_DIV0) & S3C6400_CLKDIV0_MPLL_MASK)
427 rate /= 2;
428
429 return rate;
430}
431
432static struct clk_ops clk_dout_ops = {
433 .get_rate = s3c64xx_clk_doutmpll_get_rate,
434};
435
436static struct clk clk_dout_mpll = {
437 .name = "dout_mpll",
438 .id = -1,
439 .parent = &clk_mout_mpll.clk,
440 .ops = &clk_dout_ops,
441};
442
443static struct clk *clkset_spi_mmc_list[] = {
444 &clk_mout_epll.clk,
445 &clk_dout_mpll,
446 &clk_fin_epll,
447 &clk_27m,
448};
449
450static struct clksrc_sources clkset_spi_mmc = {
451 .sources = clkset_spi_mmc_list,
452 .nr_sources = ARRAY_SIZE(clkset_spi_mmc_list),
453};
454
455static struct clk *clkset_irda_list[] = {
456 &clk_mout_epll.clk,
457 &clk_dout_mpll,
458 NULL,
459 &clk_27m,
460};
461
462static struct clksrc_sources clkset_irda = {
463 .sources = clkset_irda_list,
464 .nr_sources = ARRAY_SIZE(clkset_irda_list),
465};
466
467static struct clk *clkset_uart_list[] = {
468 &clk_mout_epll.clk,
469 &clk_dout_mpll,
470 NULL,
471 NULL
472};
473
474static struct clksrc_sources clkset_uart = {
475 .sources = clkset_uart_list,
476 .nr_sources = ARRAY_SIZE(clkset_uart_list),
477};
478
479static struct clk *clkset_uhost_list[] = {
480 &clk_48m,
481 &clk_mout_epll.clk,
482 &clk_dout_mpll,
483 &clk_fin_epll,
484};
485
486static struct clksrc_sources clkset_uhost = {
487 .sources = clkset_uhost_list,
488 .nr_sources = ARRAY_SIZE(clkset_uhost_list),
489};
490
491/* The peripheral clocks are all controlled via clocksource followed
492 * by an optional divider and gate stage. We currently roll this into
493 * one clock which hides the intermediate clock from the mux.
494 *
495 * Note, the JPEG clock can only be an even divider...
496 *
497 * The scaler and LCD clocks depend on the S3C64XX version, and also
498 * have a common parent divisor so are not included here.
499 */
500
501/* clocks that feed other parts of the clock source tree */
502
503static struct clk clk_iis_cd0 = {
504 .name = "iis_cdclk0",
505 .id = -1,
506};
507
508static struct clk clk_iis_cd1 = {
509 .name = "iis_cdclk1",
510 .id = -1,
511};
512
513static struct clk clk_pcm_cd = {
514 .name = "pcm_cdclk",
515 .id = -1,
516};
517
518static struct clk *clkset_audio0_list[] = {
519 [0] = &clk_mout_epll.clk,
520 [1] = &clk_dout_mpll,
521 [2] = &clk_fin_epll,
522 [3] = &clk_iis_cd0,
523 [4] = &clk_pcm_cd,
524};
525
526static struct clksrc_sources clkset_audio0 = {
527 .sources = clkset_audio0_list,
528 .nr_sources = ARRAY_SIZE(clkset_audio0_list),
529};
530
531static struct clk *clkset_audio1_list[] = {
532 [0] = &clk_mout_epll.clk,
533 [1] = &clk_dout_mpll,
534 [2] = &clk_fin_epll,
535 [3] = &clk_iis_cd1,
536 [4] = &clk_pcm_cd,
537};
538
539static struct clksrc_sources clkset_audio1 = {
540 .sources = clkset_audio1_list,
541 .nr_sources = ARRAY_SIZE(clkset_audio1_list),
542};
543
544static struct clk *clkset_camif_list[] = {
545 &clk_h2,
546};
547
548static struct clksrc_sources clkset_camif = {
549 .sources = clkset_camif_list,
550 .nr_sources = ARRAY_SIZE(clkset_camif_list),
551};
552
553static struct clksrc_clk clksrcs[] = {
554 {
555 .clk = {
556 .name = "mmc_bus",
557 .id = 0,
558 .ctrlbit = S3C_CLKCON_SCLK_MMC0,
559 .enable = s3c64xx_sclk_ctrl,
560 },
561 .reg_src = { .reg = S3C_CLK_SRC, .shift = 18, .size = 2 },
562 .reg_div = { .reg = S3C_CLK_DIV1, .shift = 0, .size = 4 },
563 .sources = &clkset_spi_mmc,
564 }, {
565 .clk = {
566 .name = "mmc_bus",
567 .id = 1,
568 .ctrlbit = S3C_CLKCON_SCLK_MMC1,
569 .enable = s3c64xx_sclk_ctrl,
570 },
571 .reg_src = { .reg = S3C_CLK_SRC, .shift = 20, .size = 2 },
572 .reg_div = { .reg = S3C_CLK_DIV1, .shift = 4, .size = 4 },
573 .sources = &clkset_spi_mmc,
574 }, {
575 .clk = {
576 .name = "mmc_bus",
577 .id = 2,
578 .ctrlbit = S3C_CLKCON_SCLK_MMC2,
579 .enable = s3c64xx_sclk_ctrl,
580 },
581 .reg_src = { .reg = S3C_CLK_SRC, .shift = 22, .size = 2 },
582 .reg_div = { .reg = S3C_CLK_DIV1, .shift = 8, .size = 4 },
583 .sources = &clkset_spi_mmc,
584 }, {
585 .clk = {
586 .name = "usb-bus-host",
587 .id = -1,
588 .ctrlbit = S3C_CLKCON_SCLK_UHOST,
589 .enable = s3c64xx_sclk_ctrl,
590 },
591 .reg_src = { .reg = S3C_CLK_SRC, .shift = 5, .size = 2 },
592 .reg_div = { .reg = S3C_CLK_DIV1, .shift = 20, .size = 4 },
593 .sources = &clkset_uhost,
594 }, {
595 .clk = {
596 .name = "uclk1",
597 .id = -1,
598 .ctrlbit = S3C_CLKCON_SCLK_UART,
599 .enable = s3c64xx_sclk_ctrl,
600 },
601 .reg_src = { .reg = S3C_CLK_SRC, .shift = 13, .size = 1 },
602 .reg_div = { .reg = S3C_CLK_DIV2, .shift = 16, .size = 4 },
603 .sources = &clkset_uart,
604 }, {
605/* Where does UCLK0 come from? */
606 .clk = {
607 .name = "spi-bus",
608 .id = 0,
609 .ctrlbit = S3C_CLKCON_SCLK_SPI0,
610 .enable = s3c64xx_sclk_ctrl,
611 },
612 .reg_src = { .reg = S3C_CLK_SRC, .shift = 14, .size = 2 },
613 .reg_div = { .reg = S3C_CLK_DIV2, .shift = 0, .size = 4 },
614 .sources = &clkset_spi_mmc,
615 }, {
616 .clk = {
617 .name = "spi-bus",
618 .id = 1,
619 .ctrlbit = S3C_CLKCON_SCLK_SPI1,
620 .enable = s3c64xx_sclk_ctrl,
621 },
622 .reg_src = { .reg = S3C_CLK_SRC, .shift = 16, .size = 2 },
623 .reg_div = { .reg = S3C_CLK_DIV2, .shift = 4, .size = 4 },
624 .sources = &clkset_spi_mmc,
625 }, {
626 .clk = {
627 .name = "audio-bus",
628 .id = 0,
629 .ctrlbit = S3C_CLKCON_SCLK_AUDIO0,
630 .enable = s3c64xx_sclk_ctrl,
631 },
632 .reg_src = { .reg = S3C_CLK_SRC, .shift = 7, .size = 3 },
633 .reg_div = { .reg = S3C_CLK_DIV2, .shift = 8, .size = 4 },
634 .sources = &clkset_audio0,
635 }, {
636 .clk = {
637 .name = "audio-bus",
638 .id = 1,
639 .ctrlbit = S3C_CLKCON_SCLK_AUDIO1,
640 .enable = s3c64xx_sclk_ctrl,
641 },
642 .reg_src = { .reg = S3C_CLK_SRC, .shift = 10, .size = 3 },
643 .reg_div = { .reg = S3C_CLK_DIV2, .shift = 12, .size = 4 },
644 .sources = &clkset_audio1,
645 }, {
646 .clk = {
647 .name = "irda-bus",
648 .id = 0,
649 .ctrlbit = S3C_CLKCON_SCLK_IRDA,
650 .enable = s3c64xx_sclk_ctrl,
651 },
652 .reg_src = { .reg = S3C_CLK_SRC, .shift = 24, .size = 2 },
653 .reg_div = { .reg = S3C_CLK_DIV2, .shift = 20, .size = 4 },
654 .sources = &clkset_irda,
655 }, {
656 .clk = {
657 .name = "camera",
658 .id = -1,
659 .ctrlbit = S3C_CLKCON_SCLK_CAM,
660 .enable = s3c64xx_sclk_ctrl,
661 },
662 .reg_div = { .reg = S3C_CLK_DIV0, .shift = 20, .size = 4 },
663 .reg_src = { .reg = NULL, .shift = 0, .size = 0 },
664 .sources = &clkset_camif,
665 },
666};
667
668/* Clock initialisation code */
669
670static struct clksrc_clk *init_parents[] = {
671 &clk_mout_apll,
672 &clk_mout_epll,
673 &clk_mout_mpll,
674};
675
676#define GET_DIV(clk, field) ((((clk) & field##_MASK) >> field##_SHIFT) + 1)
677
678void __init_or_cpufreq s3c6400_setup_clocks(void)
679{
680 struct clk *xtal_clk;
681 unsigned long xtal;
682 unsigned long fclk;
683 unsigned long hclk;
684 unsigned long hclk2;
685 unsigned long pclk;
686 unsigned long epll;
687 unsigned long apll;
688 unsigned long mpll;
689 unsigned int ptr;
690 u32 clkdiv0;
691
692 printk(KERN_DEBUG "%s: registering clocks\n", __func__);
693
694 clkdiv0 = __raw_readl(S3C_CLK_DIV0);
695 printk(KERN_DEBUG "%s: clkdiv0 = %08x\n", __func__, clkdiv0);
696
697 xtal_clk = clk_get(NULL, "xtal");
698 BUG_ON(IS_ERR(xtal_clk));
699
700 xtal = clk_get_rate(xtal_clk);
701 clk_put(xtal_clk);
702
703 printk(KERN_DEBUG "%s: xtal is %ld\n", __func__, xtal);
704
705 /* For now assume the mux always selects the crystal */
706 clk_ext_xtal_mux.parent = xtal_clk;
707
708 epll = s3c6400_get_epll(xtal);
709 mpll = s3c6400_get_pll(xtal, __raw_readl(S3C_MPLL_CON));
710 apll = s3c6400_get_pll(xtal, __raw_readl(S3C_APLL_CON));
711
712 fclk = mpll;
713
714 printk(KERN_INFO "S3C64XX: PLL settings, A=%ld, M=%ld, E=%ld\n",
715 apll, mpll, epll);
716
717 hclk2 = mpll / GET_DIV(clkdiv0, S3C6400_CLKDIV0_HCLK2);
718 hclk = hclk2 / GET_DIV(clkdiv0, S3C6400_CLKDIV0_HCLK);
719 pclk = hclk2 / GET_DIV(clkdiv0, S3C6400_CLKDIV0_PCLK);
720
721 printk(KERN_INFO "S3C64XX: HCLK2=%ld, HCLK=%ld, PCLK=%ld\n",
722 hclk2, hclk, pclk);
723
724 clk_fout_mpll.rate = mpll;
725 clk_fout_epll.rate = epll;
726 clk_fout_apll.rate = apll;
727
728 clk_h2.rate = hclk2;
729 clk_h.rate = hclk;
730 clk_p.rate = pclk;
731 clk_f.rate = fclk;
732
733 for (ptr = 0; ptr < ARRAY_SIZE(init_parents); ptr++)
734 s3c_set_clksrc(init_parents[ptr], true);
735
736 for (ptr = 0; ptr < ARRAY_SIZE(clksrcs); ptr++)
737 s3c_set_clksrc(&clksrcs[ptr], true);
738}
739
740static struct clk *clks1[] __initdata = {
741 &clk_ext_xtal_mux,
742 &clk_iis_cd0,
743 &clk_iis_cd1,
744 &clk_pcm_cd,
745 &clk_mout_epll.clk,
746 &clk_mout_mpll.clk,
747 &clk_dout_mpll,
748 &clk_arm,
749};
750
751/**
752 * s3c6400_register_clocks - register clocks for s3c6400 and above
753 * @armclk_divlimit: Divisor mask for ARMCLK
754 *
755 * Register the clocks for the S3C6400 and above SoC range, such
756 * as ARMCLK and the clocks which have divider chains attached.
757 *
758 * This call does not setup the clocks, which is left to the
759 * s3c6400_setup_clocks() call which may be needed by the cpufreq
760 * or resume code to re-set the clocks if the bootloader has changed
761 * them.
762 */
763void __init s3c6400_register_clocks(unsigned armclk_divlimit)
764{
765 struct clk *clkp;
766 int ret;
767 int ptr;
768
769 armclk_mask = armclk_divlimit;
770
771 for (ptr = 0; ptr < ARRAY_SIZE(clks1); ptr++) {
772 clkp = clks1[ptr];
773 ret = s3c24xx_register_clock(clkp);
774 if (ret < 0) {
775 printk(KERN_ERR "Failed to register clock %s (%d)\n",
776 clkp->name, ret);
777 }
778 }
779
780 s3c_register_clksrc(clksrcs, ARRAY_SIZE(clksrcs));
781}
782
276static struct clk *clks[] __initdata = { 783static struct clk *clks[] __initdata = {
277 &clk_ext, 784 &clk_ext,
278 &clk_epll, 785 &clk_epll,
diff --git a/arch/arm/plat-s3c64xx/Kconfig b/arch/arm/plat-s3c64xx/Kconfig
index cc300894f364..94ac74eeca5f 100644
--- a/arch/arm/plat-s3c64xx/Kconfig
+++ b/arch/arm/plat-s3c64xx/Kconfig
@@ -25,15 +25,3 @@ config PLAT_S3C64XX
25 select SAMSUNG_GPIOLIB_4BIT 25 select SAMSUNG_GPIOLIB_4BIT
26 help 26 help
27 Base platform code for any Samsung S3C64XX device 27 Base platform code for any Samsung S3C64XX device
28
29if PLAT_S3C64XX
30
31# Configuration options shared by all S3C64XX implementations
32
33config CPU_S3C6400_CLOCK
34 bool
35 help
36 Common clock support code for the S3C6400 that is shared
37 by other CPUs in the series, such as the S3C6410.
38
39endif
diff --git a/arch/arm/plat-s3c64xx/Makefile b/arch/arm/plat-s3c64xx/Makefile
index 62fc25305ec4..7ca1c0999595 100644
--- a/arch/arm/plat-s3c64xx/Makefile
+++ b/arch/arm/plat-s3c64xx/Makefile
@@ -10,6 +10,3 @@ obj-m :=
10obj-n := dummy.o 10obj-n := dummy.o
11obj- := 11obj- :=
12 12
13# CPU support
14
15obj-$(CONFIG_CPU_S3C6400_CLOCK) += s3c6400-clock.o
diff --git a/arch/arm/plat-s3c64xx/s3c6400-clock.c b/arch/arm/plat-s3c64xx/s3c6400-clock.c
deleted file mode 100644
index 85f7bb053f72..000000000000
--- a/arch/arm/plat-s3c64xx/s3c6400-clock.c
+++ /dev/null
@@ -1,536 +0,0 @@
1/* linux/arch/arm/plat-s3c64xx/s3c6400-clock.c
2 *
3 * Copyright 2008 Openmoko, Inc.
4 * Copyright 2008 Simtec Electronics
5 * Ben Dooks <ben@simtec.co.uk>
6 * http://armlinux.simtec.co.uk/
7 *
8 * S3C6400 based common clock support
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License version 2 as
12 * published by the Free Software Foundation.
13*/
14
15#include <linux/init.h>
16#include <linux/module.h>
17#include <linux/kernel.h>
18#include <linux/list.h>
19#include <linux/errno.h>
20#include <linux/err.h>
21#include <linux/clk.h>
22#include <linux/sysdev.h>
23#include <linux/io.h>
24
25#include <mach/hardware.h>
26#include <mach/map.h>
27
28#include <plat/cpu-freq.h>
29
30#include <mach/regs-clock.h>
31#include <plat/clock.h>
32#include <plat/clock-clksrc.h>
33#include <plat/cpu.h>
34#include <plat/pll.h>
35
36/* fin_apll, fin_mpll and fin_epll are all the same clock, which we call
37 * ext_xtal_mux for want of an actual name from the manual.
38*/
39
40static struct clk clk_ext_xtal_mux = {
41 .name = "ext_xtal",
42 .id = -1,
43};
44
45#define clk_fin_apll clk_ext_xtal_mux
46#define clk_fin_mpll clk_ext_xtal_mux
47#define clk_fin_epll clk_ext_xtal_mux
48
49#define clk_fout_mpll clk_mpll
50#define clk_fout_epll clk_epll
51
52static struct clk clk_fout_apll = {
53 .name = "fout_apll",
54 .id = -1,
55};
56
57static struct clk *clk_src_apll_list[] = {
58 [0] = &clk_fin_apll,
59 [1] = &clk_fout_apll,
60};
61
62static struct clksrc_sources clk_src_apll = {
63 .sources = clk_src_apll_list,
64 .nr_sources = ARRAY_SIZE(clk_src_apll_list),
65};
66
67static struct clksrc_clk clk_mout_apll = {
68 .clk = {
69 .name = "mout_apll",
70 .id = -1,
71 },
72 .reg_src = { .reg = S3C_CLK_SRC, .shift = 0, .size = 1 },
73 .sources = &clk_src_apll,
74};
75
76static struct clk *clk_src_epll_list[] = {
77 [0] = &clk_fin_epll,
78 [1] = &clk_fout_epll,
79};
80
81static struct clksrc_sources clk_src_epll = {
82 .sources = clk_src_epll_list,
83 .nr_sources = ARRAY_SIZE(clk_src_epll_list),
84};
85
86static struct clksrc_clk clk_mout_epll = {
87 .clk = {
88 .name = "mout_epll",
89 .id = -1,
90 },
91 .reg_src = { .reg = S3C_CLK_SRC, .shift = 2, .size = 1 },
92 .sources = &clk_src_epll,
93};
94
95static struct clk *clk_src_mpll_list[] = {
96 [0] = &clk_fin_mpll,
97 [1] = &clk_fout_mpll,
98};
99
100static struct clksrc_sources clk_src_mpll = {
101 .sources = clk_src_mpll_list,
102 .nr_sources = ARRAY_SIZE(clk_src_mpll_list),
103};
104
105static struct clksrc_clk clk_mout_mpll = {
106 .clk = {
107 .name = "mout_mpll",
108 .id = -1,
109 },
110 .reg_src = { .reg = S3C_CLK_SRC, .shift = 1, .size = 1 },
111 .sources = &clk_src_mpll,
112};
113
114static unsigned int armclk_mask;
115
116static unsigned long s3c64xx_clk_arm_get_rate(struct clk *clk)
117{
118 unsigned long rate = clk_get_rate(clk->parent);
119 u32 clkdiv;
120
121 /* divisor mask starts at bit0, so no need to shift */
122 clkdiv = __raw_readl(S3C_CLK_DIV0) & armclk_mask;
123
124 return rate / (clkdiv + 1);
125}
126
127static unsigned long s3c64xx_clk_arm_round_rate(struct clk *clk,
128 unsigned long rate)
129{
130 unsigned long parent = clk_get_rate(clk->parent);
131 u32 div;
132
133 if (parent < rate)
134 return parent;
135
136 div = (parent / rate) - 1;
137 if (div > armclk_mask)
138 div = armclk_mask;
139
140 return parent / (div + 1);
141}
142
143static int s3c64xx_clk_arm_set_rate(struct clk *clk, unsigned long rate)
144{
145 unsigned long parent = clk_get_rate(clk->parent);
146 u32 div;
147 u32 val;
148
149 if (rate < parent / (armclk_mask + 1))
150 return -EINVAL;
151
152 rate = clk_round_rate(clk, rate);
153 div = clk_get_rate(clk->parent) / rate;
154
155 val = __raw_readl(S3C_CLK_DIV0);
156 val &= ~armclk_mask;
157 val |= (div - 1);
158 __raw_writel(val, S3C_CLK_DIV0);
159
160 return 0;
161
162}
163
164static struct clk clk_arm = {
165 .name = "armclk",
166 .id = -1,
167 .parent = &clk_mout_apll.clk,
168 .ops = &(struct clk_ops) {
169 .get_rate = s3c64xx_clk_arm_get_rate,
170 .set_rate = s3c64xx_clk_arm_set_rate,
171 .round_rate = s3c64xx_clk_arm_round_rate,
172 },
173};
174
175static unsigned long s3c64xx_clk_doutmpll_get_rate(struct clk *clk)
176{
177 unsigned long rate = clk_get_rate(clk->parent);
178
179 printk(KERN_DEBUG "%s: parent is %ld\n", __func__, rate);
180
181 if (__raw_readl(S3C_CLK_DIV0) & S3C6400_CLKDIV0_MPLL_MASK)
182 rate /= 2;
183
184 return rate;
185}
186
187static struct clk_ops clk_dout_ops = {
188 .get_rate = s3c64xx_clk_doutmpll_get_rate,
189};
190
191static struct clk clk_dout_mpll = {
192 .name = "dout_mpll",
193 .id = -1,
194 .parent = &clk_mout_mpll.clk,
195 .ops = &clk_dout_ops,
196};
197
198static struct clk *clkset_spi_mmc_list[] = {
199 &clk_mout_epll.clk,
200 &clk_dout_mpll,
201 &clk_fin_epll,
202 &clk_27m,
203};
204
205static struct clksrc_sources clkset_spi_mmc = {
206 .sources = clkset_spi_mmc_list,
207 .nr_sources = ARRAY_SIZE(clkset_spi_mmc_list),
208};
209
210static struct clk *clkset_irda_list[] = {
211 &clk_mout_epll.clk,
212 &clk_dout_mpll,
213 NULL,
214 &clk_27m,
215};
216
217static struct clksrc_sources clkset_irda = {
218 .sources = clkset_irda_list,
219 .nr_sources = ARRAY_SIZE(clkset_irda_list),
220};
221
222static struct clk *clkset_uart_list[] = {
223 &clk_mout_epll.clk,
224 &clk_dout_mpll,
225 NULL,
226 NULL
227};
228
229static struct clksrc_sources clkset_uart = {
230 .sources = clkset_uart_list,
231 .nr_sources = ARRAY_SIZE(clkset_uart_list),
232};
233
234static struct clk *clkset_uhost_list[] = {
235 &clk_48m,
236 &clk_mout_epll.clk,
237 &clk_dout_mpll,
238 &clk_fin_epll,
239};
240
241static struct clksrc_sources clkset_uhost = {
242 .sources = clkset_uhost_list,
243 .nr_sources = ARRAY_SIZE(clkset_uhost_list),
244};
245
246/* The peripheral clocks are all controlled via clocksource followed
247 * by an optional divider and gate stage. We currently roll this into
248 * one clock which hides the intermediate clock from the mux.
249 *
250 * Note, the JPEG clock can only be an even divider...
251 *
252 * The scaler and LCD clocks depend on the S3C64XX version, and also
253 * have a common parent divisor so are not included here.
254 */
255
256/* clocks that feed other parts of the clock source tree */
257
258static struct clk clk_iis_cd0 = {
259 .name = "iis_cdclk0",
260 .id = -1,
261};
262
263static struct clk clk_iis_cd1 = {
264 .name = "iis_cdclk1",
265 .id = -1,
266};
267
268static struct clk clk_pcm_cd = {
269 .name = "pcm_cdclk",
270 .id = -1,
271};
272
273static struct clk *clkset_audio0_list[] = {
274 [0] = &clk_mout_epll.clk,
275 [1] = &clk_dout_mpll,
276 [2] = &clk_fin_epll,
277 [3] = &clk_iis_cd0,
278 [4] = &clk_pcm_cd,
279};
280
281static struct clksrc_sources clkset_audio0 = {
282 .sources = clkset_audio0_list,
283 .nr_sources = ARRAY_SIZE(clkset_audio0_list),
284};
285
286static struct clk *clkset_audio1_list[] = {
287 [0] = &clk_mout_epll.clk,
288 [1] = &clk_dout_mpll,
289 [2] = &clk_fin_epll,
290 [3] = &clk_iis_cd1,
291 [4] = &clk_pcm_cd,
292};
293
294static struct clksrc_sources clkset_audio1 = {
295 .sources = clkset_audio1_list,
296 .nr_sources = ARRAY_SIZE(clkset_audio1_list),
297};
298
299static struct clk *clkset_camif_list[] = {
300 &clk_h2,
301};
302
303static struct clksrc_sources clkset_camif = {
304 .sources = clkset_camif_list,
305 .nr_sources = ARRAY_SIZE(clkset_camif_list),
306};
307
308static struct clksrc_clk clksrcs[] = {
309 {
310 .clk = {
311 .name = "mmc_bus",
312 .id = 0,
313 .ctrlbit = S3C_CLKCON_SCLK_MMC0,
314 .enable = s3c64xx_sclk_ctrl,
315 },
316 .reg_src = { .reg = S3C_CLK_SRC, .shift = 18, .size = 2 },
317 .reg_div = { .reg = S3C_CLK_DIV1, .shift = 0, .size = 4 },
318 .sources = &clkset_spi_mmc,
319 }, {
320 .clk = {
321 .name = "mmc_bus",
322 .id = 1,
323 .ctrlbit = S3C_CLKCON_SCLK_MMC1,
324 .enable = s3c64xx_sclk_ctrl,
325 },
326 .reg_src = { .reg = S3C_CLK_SRC, .shift = 20, .size = 2 },
327 .reg_div = { .reg = S3C_CLK_DIV1, .shift = 4, .size = 4 },
328 .sources = &clkset_spi_mmc,
329 }, {
330 .clk = {
331 .name = "mmc_bus",
332 .id = 2,
333 .ctrlbit = S3C_CLKCON_SCLK_MMC2,
334 .enable = s3c64xx_sclk_ctrl,
335 },
336 .reg_src = { .reg = S3C_CLK_SRC, .shift = 22, .size = 2 },
337 .reg_div = { .reg = S3C_CLK_DIV1, .shift = 8, .size = 4 },
338 .sources = &clkset_spi_mmc,
339 }, {
340 .clk = {
341 .name = "usb-bus-host",
342 .id = -1,
343 .ctrlbit = S3C_CLKCON_SCLK_UHOST,
344 .enable = s3c64xx_sclk_ctrl,
345 },
346 .reg_src = { .reg = S3C_CLK_SRC, .shift = 5, .size = 2 },
347 .reg_div = { .reg = S3C_CLK_DIV1, .shift = 20, .size = 4 },
348 .sources = &clkset_uhost,
349 }, {
350 .clk = {
351 .name = "uclk1",
352 .id = -1,
353 .ctrlbit = S3C_CLKCON_SCLK_UART,
354 .enable = s3c64xx_sclk_ctrl,
355 },
356 .reg_src = { .reg = S3C_CLK_SRC, .shift = 13, .size = 1 },
357 .reg_div = { .reg = S3C_CLK_DIV2, .shift = 16, .size = 4 },
358 .sources = &clkset_uart,
359 }, {
360/* Where does UCLK0 come from? */
361 .clk = {
362 .name = "spi-bus",
363 .id = 0,
364 .ctrlbit = S3C_CLKCON_SCLK_SPI0,
365 .enable = s3c64xx_sclk_ctrl,
366 },
367 .reg_src = { .reg = S3C_CLK_SRC, .shift = 14, .size = 2 },
368 .reg_div = { .reg = S3C_CLK_DIV2, .shift = 0, .size = 4 },
369 .sources = &clkset_spi_mmc,
370 }, {
371 .clk = {
372 .name = "spi-bus",
373 .id = 1,
374 .ctrlbit = S3C_CLKCON_SCLK_SPI1,
375 .enable = s3c64xx_sclk_ctrl,
376 },
377 .reg_src = { .reg = S3C_CLK_SRC, .shift = 16, .size = 2 },
378 .reg_div = { .reg = S3C_CLK_DIV2, .shift = 4, .size = 4 },
379 .sources = &clkset_spi_mmc,
380 }, {
381 .clk = {
382 .name = "audio-bus",
383 .id = 0,
384 .ctrlbit = S3C_CLKCON_SCLK_AUDIO0,
385 .enable = s3c64xx_sclk_ctrl,
386 },
387 .reg_src = { .reg = S3C_CLK_SRC, .shift = 7, .size = 3 },
388 .reg_div = { .reg = S3C_CLK_DIV2, .shift = 8, .size = 4 },
389 .sources = &clkset_audio0,
390 }, {
391 .clk = {
392 .name = "audio-bus",
393 .id = 1,
394 .ctrlbit = S3C_CLKCON_SCLK_AUDIO1,
395 .enable = s3c64xx_sclk_ctrl,
396 },
397 .reg_src = { .reg = S3C_CLK_SRC, .shift = 10, .size = 3 },
398 .reg_div = { .reg = S3C_CLK_DIV2, .shift = 12, .size = 4 },
399 .sources = &clkset_audio1,
400 }, {
401 .clk = {
402 .name = "irda-bus",
403 .id = 0,
404 .ctrlbit = S3C_CLKCON_SCLK_IRDA,
405 .enable = s3c64xx_sclk_ctrl,
406 },
407 .reg_src = { .reg = S3C_CLK_SRC, .shift = 24, .size = 2 },
408 .reg_div = { .reg = S3C_CLK_DIV2, .shift = 20, .size = 4 },
409 .sources = &clkset_irda,
410 }, {
411 .clk = {
412 .name = "camera",
413 .id = -1,
414 .ctrlbit = S3C_CLKCON_SCLK_CAM,
415 .enable = s3c64xx_sclk_ctrl,
416 },
417 .reg_div = { .reg = S3C_CLK_DIV0, .shift = 20, .size = 4 },
418 .reg_src = { .reg = NULL, .shift = 0, .size = 0 },
419 .sources = &clkset_camif,
420 },
421};
422
423/* Clock initialisation code */
424
425static struct clksrc_clk *init_parents[] = {
426 &clk_mout_apll,
427 &clk_mout_epll,
428 &clk_mout_mpll,
429};
430
431#define GET_DIV(clk, field) ((((clk) & field##_MASK) >> field##_SHIFT) + 1)
432
433void __init_or_cpufreq s3c6400_setup_clocks(void)
434{
435 struct clk *xtal_clk;
436 unsigned long xtal;
437 unsigned long fclk;
438 unsigned long hclk;
439 unsigned long hclk2;
440 unsigned long pclk;
441 unsigned long epll;
442 unsigned long apll;
443 unsigned long mpll;
444 unsigned int ptr;
445 u32 clkdiv0;
446
447 printk(KERN_DEBUG "%s: registering clocks\n", __func__);
448
449 clkdiv0 = __raw_readl(S3C_CLK_DIV0);
450 printk(KERN_DEBUG "%s: clkdiv0 = %08x\n", __func__, clkdiv0);
451
452 xtal_clk = clk_get(NULL, "xtal");
453 BUG_ON(IS_ERR(xtal_clk));
454
455 xtal = clk_get_rate(xtal_clk);
456 clk_put(xtal_clk);
457
458 printk(KERN_DEBUG "%s: xtal is %ld\n", __func__, xtal);
459
460 /* For now assume the mux always selects the crystal */
461 clk_ext_xtal_mux.parent = xtal_clk;
462
463 epll = s3c6400_get_epll(xtal);
464 mpll = s3c6400_get_pll(xtal, __raw_readl(S3C_MPLL_CON));
465 apll = s3c6400_get_pll(xtal, __raw_readl(S3C_APLL_CON));
466
467 fclk = mpll;
468
469 printk(KERN_INFO "S3C64XX: PLL settings, A=%ld, M=%ld, E=%ld\n",
470 apll, mpll, epll);
471
472 hclk2 = mpll / GET_DIV(clkdiv0, S3C6400_CLKDIV0_HCLK2);
473 hclk = hclk2 / GET_DIV(clkdiv0, S3C6400_CLKDIV0_HCLK);
474 pclk = hclk2 / GET_DIV(clkdiv0, S3C6400_CLKDIV0_PCLK);
475
476 printk(KERN_INFO "S3C64XX: HCLK2=%ld, HCLK=%ld, PCLK=%ld\n",
477 hclk2, hclk, pclk);
478
479 clk_fout_mpll.rate = mpll;
480 clk_fout_epll.rate = epll;
481 clk_fout_apll.rate = apll;
482
483 clk_h2.rate = hclk2;
484 clk_h.rate = hclk;
485 clk_p.rate = pclk;
486 clk_f.rate = fclk;
487
488 for (ptr = 0; ptr < ARRAY_SIZE(init_parents); ptr++)
489 s3c_set_clksrc(init_parents[ptr], true);
490
491 for (ptr = 0; ptr < ARRAY_SIZE(clksrcs); ptr++)
492 s3c_set_clksrc(&clksrcs[ptr], true);
493}
494
495static struct clk *clks[] __initdata = {
496 &clk_ext_xtal_mux,
497 &clk_iis_cd0,
498 &clk_iis_cd1,
499 &clk_pcm_cd,
500 &clk_mout_epll.clk,
501 &clk_mout_mpll.clk,
502 &clk_dout_mpll,
503 &clk_arm,
504};
505
506/**
507 * s3c6400_register_clocks - register clocks for s3c6400 and above
508 * @armclk_divlimit: Divisor mask for ARMCLK
509 *
510 * Register the clocks for the S3C6400 and above SoC range, such
511 * as ARMCLK and the clocks which have divider chains attached.
512 *
513 * This call does not setup the clocks, which is left to the
514 * s3c6400_setup_clocks() call which may be needed by the cpufreq
515 * or resume code to re-set the clocks if the bootloader has changed
516 * them.
517 */
518void __init s3c6400_register_clocks(unsigned armclk_divlimit)
519{
520 struct clk *clkp;
521 int ret;
522 int ptr;
523
524 armclk_mask = armclk_divlimit;
525
526 for (ptr = 0; ptr < ARRAY_SIZE(clks); ptr++) {
527 clkp = clks[ptr];
528 ret = s3c24xx_register_clock(clkp);
529 if (ret < 0) {
530 printk(KERN_ERR "Failed to register clock %s (%d)\n",
531 clkp->name, ret);
532 }
533 }
534
535 s3c_register_clksrc(clksrcs, ARRAY_SIZE(clksrcs));
536}