diff options
Diffstat (limited to 'arch/arm/mach-s3c2443/clock.c')
-rw-r--r-- | arch/arm/mach-s3c2443/clock.c | 91 |
1 files changed, 85 insertions, 6 deletions
diff --git a/arch/arm/mach-s3c2443/clock.c b/arch/arm/mach-s3c2443/clock.c index b42f956738d0..17f064fabdaf 100644 --- a/arch/arm/mach-s3c2443/clock.c +++ b/arch/arm/mach-s3c2443/clock.c | |||
@@ -81,7 +81,7 @@ static int s3c2443_clkcon_enable_p(struct clk *clk, int enable) | |||
81 | else | 81 | else |
82 | clkcon &= ~clocks; | 82 | clkcon &= ~clocks; |
83 | 83 | ||
84 | __raw_writel(clkcon, S3C2443_HCLKCON); | 84 | __raw_writel(clkcon, S3C2443_PCLKCON); |
85 | 85 | ||
86 | return 0; | 86 | return 0; |
87 | } | 87 | } |
@@ -221,7 +221,6 @@ static struct clk clk_mdivclk = { | |||
221 | .get_rate = s3c2443_getrate_mdivclk, | 221 | .get_rate = s3c2443_getrate_mdivclk, |
222 | }; | 222 | }; |
223 | 223 | ||
224 | |||
225 | static int s3c2443_setparent_msysclk(struct clk *clk, struct clk *parent) | 224 | static int s3c2443_setparent_msysclk(struct clk *clk, struct clk *parent) |
226 | { | 225 | { |
227 | unsigned long clksrc = __raw_readl(S3C2443_CLKSRC); | 226 | unsigned long clksrc = __raw_readl(S3C2443_CLKSRC); |
@@ -249,6 +248,46 @@ static struct clk clk_msysclk = { | |||
249 | .set_parent = s3c2443_setparent_msysclk, | 248 | .set_parent = s3c2443_setparent_msysclk, |
250 | }; | 249 | }; |
251 | 250 | ||
251 | /* armdiv | ||
252 | * | ||
253 | * this clock is sourced from msysclk and can have a number of | ||
254 | * divider values applied to it to then be fed into armclk. | ||
255 | */ | ||
256 | |||
257 | static struct clk clk_armdiv = { | ||
258 | .name = "armdiv", | ||
259 | .id = -1, | ||
260 | .parent = &clk_msysclk, | ||
261 | }; | ||
262 | |||
263 | /* armclk | ||
264 | * | ||
265 | * this is the clock fed into the ARM core itself, either from | ||
266 | * armdiv or from hclk. | ||
267 | */ | ||
268 | |||
269 | static int s3c2443_setparent_armclk(struct clk *clk, struct clk *parent) | ||
270 | { | ||
271 | unsigned long clkdiv0; | ||
272 | |||
273 | clkdiv0 = __raw_readl(S3C2443_CLKDIV0); | ||
274 | |||
275 | if (parent == &clk_armdiv) | ||
276 | clkdiv0 &= ~S3C2443_CLKDIV0_DVS; | ||
277 | else if (parent == &clk_h) | ||
278 | clkdiv0 |= S3C2443_CLKDIV0_DVS; | ||
279 | else | ||
280 | return -EINVAL; | ||
281 | |||
282 | __raw_writel(clkdiv0, S3C2443_CLKDIV0); | ||
283 | return 0; | ||
284 | } | ||
285 | |||
286 | static struct clk clk_arm = { | ||
287 | .name = "armclk", | ||
288 | .id = -1, | ||
289 | .set_parent = s3c2443_setparent_armclk, | ||
290 | }; | ||
252 | 291 | ||
253 | /* esysclk | 292 | /* esysclk |
254 | * | 293 | * |
@@ -639,6 +678,29 @@ static struct clk clk_display = { | |||
639 | .round_rate = s3c2443_roundrate_clksrc256, | 678 | .round_rate = s3c2443_roundrate_clksrc256, |
640 | }; | 679 | }; |
641 | 680 | ||
681 | /* prediv | ||
682 | * | ||
683 | * this divides the msysclk down to pass to h/p/etc. | ||
684 | */ | ||
685 | |||
686 | static unsigned long s3c2443_prediv_getrate(struct clk *clk) | ||
687 | { | ||
688 | unsigned long rate = clk_get_rate(clk->parent); | ||
689 | unsigned long clkdiv0 = __raw_readl(S3C2443_CLKDIV0); | ||
690 | |||
691 | clkdiv0 &= S3C2443_CLKDIV0_PREDIV_MASK; | ||
692 | clkdiv0 >>= S3C2443_CLKDIV0_PREDIV_SHIFT; | ||
693 | |||
694 | return rate / (clkdiv0 + 1); | ||
695 | } | ||
696 | |||
697 | static struct clk clk_prediv = { | ||
698 | .name = "prediv", | ||
699 | .id = -1, | ||
700 | .parent = &clk_msysclk, | ||
701 | .get_rate = s3c2443_prediv_getrate, | ||
702 | }; | ||
703 | |||
642 | /* standard clock definitions */ | 704 | /* standard clock definitions */ |
643 | 705 | ||
644 | static struct clk init_clocks_disable[] = { | 706 | static struct clk init_clocks_disable[] = { |
@@ -887,6 +949,15 @@ static void __init s3c2443_clk_initparents(void) | |||
887 | } | 949 | } |
888 | 950 | ||
889 | clk_init_set_parent(&clk_msysclk, parent); | 951 | clk_init_set_parent(&clk_msysclk, parent); |
952 | |||
953 | /* arm */ | ||
954 | |||
955 | if (__raw_readl(S3C2443_CLKDIV0) & S3C2443_CLKDIV0_DVS) | ||
956 | parent = &clk_h; | ||
957 | else | ||
958 | parent = &clk_armdiv; | ||
959 | |||
960 | clk_init_set_parent(&clk_arm, parent); | ||
890 | } | 961 | } |
891 | 962 | ||
892 | /* armdiv divisor table */ | 963 | /* armdiv divisor table */ |
@@ -909,10 +980,9 @@ static inline unsigned int s3c2443_fclk_div(unsigned long clkcon0) | |||
909 | return armdiv[clkcon0 >> S3C2443_CLKDIV0_ARMDIV_SHIFT]; | 980 | return armdiv[clkcon0 >> S3C2443_CLKDIV0_ARMDIV_SHIFT]; |
910 | } | 981 | } |
911 | 982 | ||
912 | static inline unsigned long s3c2443_get_prediv(unsigned long clkcon0) | 983 | static inline unsigned long s3c2443_get_hdiv(unsigned long clkcon0) |
913 | { | 984 | { |
914 | clkcon0 &= S3C2443_CLKDIV0_PREDIV_MASK; | 985 | clkcon0 &= S3C2443_CLKDIV0_HCLKDIV_MASK; |
915 | clkcon0 >>= S3C2443_CLKDIV0_PREDIV_SHIFT; | ||
916 | 986 | ||
917 | return clkcon0 + 1; | 987 | return clkcon0 + 1; |
918 | } | 988 | } |
@@ -936,6 +1006,9 @@ static struct clk *clks[] __initdata = { | |||
936 | &clk_hsspi, | 1006 | &clk_hsspi, |
937 | &clk_hsmmc_div, | 1007 | &clk_hsmmc_div, |
938 | &clk_hsmmc, | 1008 | &clk_hsmmc, |
1009 | &clk_armdiv, | ||
1010 | &clk_arm, | ||
1011 | &clk_prediv, | ||
939 | }; | 1012 | }; |
940 | 1013 | ||
941 | void __init s3c2443_init_clocks(int xtal) | 1014 | void __init s3c2443_init_clocks(int xtal) |
@@ -951,10 +1024,16 @@ void __init s3c2443_init_clocks(int xtal) | |||
951 | int ret; | 1024 | int ret; |
952 | int ptr; | 1025 | int ptr; |
953 | 1026 | ||
1027 | /* s3c2443 parents h and p clocks from prediv */ | ||
1028 | clk_h.parent = &clk_prediv; | ||
1029 | clk_p.parent = &clk_prediv; | ||
1030 | |||
954 | pll = s3c2443_get_mpll(mpllcon, xtal); | 1031 | pll = s3c2443_get_mpll(mpllcon, xtal); |
1032 | clk_msysclk.rate = pll; | ||
955 | 1033 | ||
956 | fclk = pll / s3c2443_fclk_div(clkdiv0); | 1034 | fclk = pll / s3c2443_fclk_div(clkdiv0); |
957 | hclk = fclk / s3c2443_get_prediv(clkdiv0); | 1035 | hclk = s3c2443_prediv_getrate(&clk_prediv); |
1036 | hclk = hclk / s3c2443_get_hdiv(clkdiv0); | ||
958 | hclk = hclk / ((clkdiv0 & S3C2443_CLKDIV0_HALF_HCLK) ? 2 : 1); | 1037 | hclk = hclk / ((clkdiv0 & S3C2443_CLKDIV0_HALF_HCLK) ? 2 : 1); |
959 | pclk = hclk / ((clkdiv0 & S3C2443_CLKDIV0_HALF_PCLK) ? 2 : 1); | 1038 | pclk = hclk / ((clkdiv0 & S3C2443_CLKDIV0_HALF_PCLK) ? 2 : 1); |
960 | 1039 | ||