1 /* linux/arch/arm/mach-s5pv310/clock.c
3 * Copyright (c) 2010 Samsung Electronics Co., Ltd.
4 * http://www.samsung.com/
6 * S5PV310 - Clock support
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
13 #include <linux/kernel.h>
14 #include <linux/err.h>
17 #include <plat/cpu-freq.h>
18 #include <plat/clock.h>
21 #include <plat/s5p-clock.h>
22 #include <plat/clock-clksrc.h>
25 #include <mach/regs-clock.h>
27 static struct clk clk_sclk_hdmi27m
= {
28 .name
= "sclk_hdmi27m",
33 static int s5pv310_clksrc_mask_peril0_ctrl(struct clk
*clk
, int enable
)
35 return s5p_gatectrl(S5P_CLKSRC_MASK_PERIL0
, clk
, enable
);
38 static int s5pv310_clk_ip_peril_ctrl(struct clk
*clk
, int enable
)
40 return s5p_gatectrl(S5P_CLKGATE_IP_PERIL
, clk
, enable
);
43 /* Core list of CMU_CPU side */
45 static struct clksrc_clk clk_mout_apll
= {
50 .sources
= &clk_src_apll
,
51 .reg_src
= { .reg
= S5P_CLKSRC_CPU
, .shift
= 0, .size
= 1 },
54 static struct clksrc_clk clk_sclk_apll
= {
58 .parent
= &clk_mout_apll
.clk
,
60 .reg_div
= { .reg
= S5P_CLKDIV_CPU
, .shift
= 24, .size
= 3 },
63 static struct clksrc_clk clk_mout_epll
= {
68 .sources
= &clk_src_epll
,
69 .reg_src
= { .reg
= S5P_CLKSRC_TOP0
, .shift
= 4, .size
= 1 },
72 static struct clksrc_clk clk_mout_mpll
= {
77 .sources
= &clk_src_mpll
,
78 .reg_src
= { .reg
= S5P_CLKSRC_CPU
, .shift
= 8, .size
= 1 },
81 static struct clk
*clkset_moutcore_list
[] = {
82 [0] = &clk_sclk_apll
.clk
,
83 [1] = &clk_mout_mpll
.clk
,
86 static struct clksrc_sources clkset_moutcore
= {
87 .sources
= clkset_moutcore_list
,
88 .nr_sources
= ARRAY_SIZE(clkset_moutcore_list
),
91 static struct clksrc_clk clk_moutcore
= {
96 .sources
= &clkset_moutcore
,
97 .reg_src
= { .reg
= S5P_CLKSRC_CPU
, .shift
= 16, .size
= 1 },
100 static struct clksrc_clk clk_coreclk
= {
104 .parent
= &clk_moutcore
.clk
,
106 .reg_div
= { .reg
= S5P_CLKDIV_CPU
, .shift
= 0, .size
= 3 },
109 static struct clksrc_clk clk_armclk
= {
113 .parent
= &clk_coreclk
.clk
,
117 static struct clksrc_clk clk_aclk_corem0
= {
119 .name
= "aclk_corem0",
121 .parent
= &clk_coreclk
.clk
,
123 .reg_div
= { .reg
= S5P_CLKDIV_CPU
, .shift
= 4, .size
= 3 },
126 static struct clksrc_clk clk_aclk_cores
= {
128 .name
= "aclk_cores",
130 .parent
= &clk_coreclk
.clk
,
132 .reg_div
= { .reg
= S5P_CLKDIV_CPU
, .shift
= 4, .size
= 3 },
135 static struct clksrc_clk clk_aclk_corem1
= {
137 .name
= "aclk_corem1",
139 .parent
= &clk_coreclk
.clk
,
141 .reg_div
= { .reg
= S5P_CLKDIV_CPU
, .shift
= 8, .size
= 3 },
144 static struct clksrc_clk clk_periphclk
= {
148 .parent
= &clk_coreclk
.clk
,
150 .reg_div
= { .reg
= S5P_CLKDIV_CPU
, .shift
= 12, .size
= 3 },
153 static struct clksrc_clk clk_atclk
= {
157 .parent
= &clk_moutcore
.clk
,
159 .reg_div
= { .reg
= S5P_CLKDIV_CPU
, .shift
= 16, .size
= 3 },
162 static struct clksrc_clk clk_pclk_dbg
= {
166 .parent
= &clk_atclk
.clk
,
168 .reg_div
= { .reg
= S5P_CLKDIV_CPU
, .shift
= 20, .size
= 3 },
171 /* Core list of CMU_CORE side */
173 static struct clk
*clkset_corebus_list
[] = {
174 [0] = &clk_mout_mpll
.clk
,
175 [1] = &clk_sclk_apll
.clk
,
178 static struct clksrc_sources clkset_mout_corebus
= {
179 .sources
= clkset_corebus_list
,
180 .nr_sources
= ARRAY_SIZE(clkset_corebus_list
),
183 static struct clksrc_clk clk_mout_corebus
= {
185 .name
= "mout_corebus",
188 .sources
= &clkset_mout_corebus
,
189 .reg_src
= { .reg
= S5P_CLKSRC_CORE
, .shift
= 4, .size
= 1 },
192 static struct clksrc_clk clk_sclk_dmc
= {
196 .parent
= &clk_mout_corebus
.clk
,
198 .reg_div
= { .reg
= S5P_CLKDIV_CORE0
, .shift
= 12, .size
= 3 },
201 static struct clksrc_clk clk_aclk_cored
= {
203 .name
= "aclk_cored",
205 .parent
= &clk_sclk_dmc
.clk
,
207 .reg_div
= { .reg
= S5P_CLKDIV_CORE0
, .shift
= 16, .size
= 3 },
210 static struct clksrc_clk clk_aclk_corep
= {
212 .name
= "aclk_corep",
214 .parent
= &clk_aclk_cored
.clk
,
216 .reg_div
= { .reg
= S5P_CLKDIV_CORE0
, .shift
= 20, .size
= 3 },
219 static struct clksrc_clk clk_aclk_acp
= {
223 .parent
= &clk_mout_corebus
.clk
,
225 .reg_div
= { .reg
= S5P_CLKDIV_CORE0
, .shift
= 0, .size
= 3 },
228 static struct clksrc_clk clk_pclk_acp
= {
232 .parent
= &clk_aclk_acp
.clk
,
234 .reg_div
= { .reg
= S5P_CLKDIV_CORE0
, .shift
= 4, .size
= 3 },
237 /* Core list of CMU_TOP side */
239 static struct clk
*clkset_aclk_top_list
[] = {
240 [0] = &clk_mout_mpll
.clk
,
241 [1] = &clk_sclk_apll
.clk
,
244 static struct clksrc_sources clkset_aclk_200
= {
245 .sources
= clkset_aclk_top_list
,
246 .nr_sources
= ARRAY_SIZE(clkset_aclk_top_list
),
249 static struct clksrc_clk clk_aclk_200
= {
254 .sources
= &clkset_aclk_200
,
255 .reg_src
= { .reg
= S5P_CLKSRC_TOP0
, .shift
= 12, .size
= 1 },
256 .reg_div
= { .reg
= S5P_CLKDIV_TOP
, .shift
= 0, .size
= 3 },
259 static struct clksrc_sources clkset_aclk_100
= {
260 .sources
= clkset_aclk_top_list
,
261 .nr_sources
= ARRAY_SIZE(clkset_aclk_top_list
),
264 static struct clksrc_clk clk_aclk_100
= {
269 .sources
= &clkset_aclk_100
,
270 .reg_src
= { .reg
= S5P_CLKSRC_TOP0
, .shift
= 16, .size
= 1 },
271 .reg_div
= { .reg
= S5P_CLKDIV_TOP
, .shift
= 4, .size
= 4 },
274 static struct clksrc_sources clkset_aclk_160
= {
275 .sources
= clkset_aclk_top_list
,
276 .nr_sources
= ARRAY_SIZE(clkset_aclk_top_list
),
279 static struct clksrc_clk clk_aclk_160
= {
284 .sources
= &clkset_aclk_160
,
285 .reg_src
= { .reg
= S5P_CLKSRC_TOP0
, .shift
= 20, .size
= 1 },
286 .reg_div
= { .reg
= S5P_CLKDIV_TOP
, .shift
= 8, .size
= 3 },
289 static struct clksrc_sources clkset_aclk_133
= {
290 .sources
= clkset_aclk_top_list
,
291 .nr_sources
= ARRAY_SIZE(clkset_aclk_top_list
),
294 static struct clksrc_clk clk_aclk_133
= {
299 .sources
= &clkset_aclk_133
,
300 .reg_src
= { .reg
= S5P_CLKSRC_TOP0
, .shift
= 24, .size
= 1 },
301 .reg_div
= { .reg
= S5P_CLKDIV_TOP
, .shift
= 12, .size
= 3 },
304 static struct clk
*clkset_vpllsrc_list
[] = {
306 [1] = &clk_sclk_hdmi27m
,
309 static struct clksrc_sources clkset_vpllsrc
= {
310 .sources
= clkset_vpllsrc_list
,
311 .nr_sources
= ARRAY_SIZE(clkset_vpllsrc_list
),
314 static struct clksrc_clk clk_vpllsrc
= {
319 .sources
= &clkset_vpllsrc
,
320 .reg_src
= { .reg
= S5P_CLKSRC_TOP1
, .shift
= 0, .size
= 1 },
323 static struct clk
*clkset_sclk_vpll_list
[] = {
324 [0] = &clk_vpllsrc
.clk
,
325 [1] = &clk_fout_vpll
,
328 static struct clksrc_sources clkset_sclk_vpll
= {
329 .sources
= clkset_sclk_vpll_list
,
330 .nr_sources
= ARRAY_SIZE(clkset_sclk_vpll_list
),
333 static struct clksrc_clk clk_sclk_vpll
= {
338 .sources
= &clkset_sclk_vpll
,
339 .reg_src
= { .reg
= S5P_CLKSRC_TOP0
, .shift
= 8, .size
= 1 },
342 static struct clk init_clocks_disable
[] = {
346 .parent
= &clk_aclk_100
.clk
,
347 .enable
= s5pv310_clk_ip_peril_ctrl
,
352 static struct clk init_clocks
[] = {
356 .enable
= s5pv310_clk_ip_peril_ctrl
,
361 .enable
= s5pv310_clk_ip_peril_ctrl
,
366 .enable
= s5pv310_clk_ip_peril_ctrl
,
371 .enable
= s5pv310_clk_ip_peril_ctrl
,
376 .enable
= s5pv310_clk_ip_peril_ctrl
,
381 .enable
= s5pv310_clk_ip_peril_ctrl
,
386 static struct clk
*clkset_group_list
[] = {
387 [0] = &clk_ext_xtal_mux
,
389 [2] = &clk_sclk_hdmi27m
,
390 [6] = &clk_mout_mpll
.clk
,
391 [7] = &clk_mout_epll
.clk
,
392 [8] = &clk_sclk_vpll
.clk
,
395 static struct clksrc_sources clkset_group
= {
396 .sources
= clkset_group_list
,
397 .nr_sources
= ARRAY_SIZE(clkset_group_list
),
400 static struct clksrc_clk clksrcs
[] = {
405 .enable
= s5pv310_clksrc_mask_peril0_ctrl
,
408 .sources
= &clkset_group
,
409 .reg_src
= { .reg
= S5P_CLKSRC_PERIL0
, .shift
= 0, .size
= 4 },
410 .reg_div
= { .reg
= S5P_CLKDIV_PERIL0
, .shift
= 0, .size
= 4 },
415 .enable
= s5pv310_clksrc_mask_peril0_ctrl
,
418 .sources
= &clkset_group
,
419 .reg_src
= { .reg
= S5P_CLKSRC_PERIL0
, .shift
= 4, .size
= 4 },
420 .reg_div
= { .reg
= S5P_CLKDIV_PERIL0
, .shift
= 4, .size
= 4 },
425 .enable
= s5pv310_clksrc_mask_peril0_ctrl
,
428 .sources
= &clkset_group
,
429 .reg_src
= { .reg
= S5P_CLKSRC_PERIL0
, .shift
= 8, .size
= 4 },
430 .reg_div
= { .reg
= S5P_CLKDIV_PERIL0
, .shift
= 8, .size
= 4 },
435 .enable
= s5pv310_clksrc_mask_peril0_ctrl
,
436 .ctrlbit
= (1 << 12),
438 .sources
= &clkset_group
,
439 .reg_src
= { .reg
= S5P_CLKSRC_PERIL0
, .shift
= 12, .size
= 4 },
440 .reg_div
= { .reg
= S5P_CLKDIV_PERIL0
, .shift
= 12, .size
= 4 },
445 .enable
= s5pv310_clksrc_mask_peril0_ctrl
,
446 .ctrlbit
= (1 << 24),
448 .sources
= &clkset_group
,
449 .reg_src
= { .reg
= S5P_CLKSRC_PERIL0
, .shift
= 24, .size
= 4 },
450 .reg_div
= { .reg
= S5P_CLKDIV_PERIL3
, .shift
= 0, .size
= 4 },
454 /* Clock initialization code */
455 static struct clksrc_clk
*sysclks
[] = {
483 void __init_or_cpufreq
s5pv310_setup_clocks(void)
485 struct clk
*xtal_clk
;
490 unsigned long vpllsrc
;
492 unsigned long armclk
;
493 unsigned long aclk_corem0
;
494 unsigned long aclk_cores
;
495 unsigned long aclk_corem1
;
496 unsigned long periphclk
;
497 unsigned long sclk_dmc
;
498 unsigned long aclk_cored
;
499 unsigned long aclk_corep
;
500 unsigned long aclk_acp
;
501 unsigned long pclk_acp
;
504 printk(KERN_DEBUG
"%s: registering clocks\n", __func__
);
506 xtal_clk
= clk_get(NULL
, "xtal");
507 BUG_ON(IS_ERR(xtal_clk
));
509 xtal
= clk_get_rate(xtal_clk
);
512 printk(KERN_DEBUG
"%s: xtal is %ld\n", __func__
, xtal
);
514 apll
= s5p_get_pll45xx(xtal
, __raw_readl(S5P_APLL_CON0
), pll_4508
);
515 mpll
= s5p_get_pll45xx(xtal
, __raw_readl(S5P_MPLL_CON0
), pll_4508
);
516 epll
= s5p_get_pll46xx(xtal
, __raw_readl(S5P_EPLL_CON0
),
517 __raw_readl(S5P_EPLL_CON1
), pll_4600
);
519 vpllsrc
= clk_get_rate(&clk_vpllsrc
.clk
);
520 vpll
= s5p_get_pll46xx(vpllsrc
, __raw_readl(S5P_VPLL_CON0
),
521 __raw_readl(S5P_VPLL_CON1
), pll_4650
);
523 clk_fout_apll
.rate
= apll
;
524 clk_fout_mpll
.rate
= mpll
;
525 clk_fout_epll
.rate
= epll
;
526 clk_fout_vpll
.rate
= vpll
;
528 printk(KERN_INFO
"S5PV310: PLL settings, A=%ld, M=%ld, E=%ld V=%ld",
529 apll
, mpll
, epll
, vpll
);
531 armclk
= clk_get_rate(&clk_armclk
.clk
);
532 aclk_corem0
= clk_get_rate(&clk_aclk_corem0
.clk
);
533 aclk_cores
= clk_get_rate(&clk_aclk_cores
.clk
);
534 aclk_corem1
= clk_get_rate(&clk_aclk_corem1
.clk
);
535 periphclk
= clk_get_rate(&clk_periphclk
.clk
);
536 sclk_dmc
= clk_get_rate(&clk_sclk_dmc
.clk
);
537 aclk_cored
= clk_get_rate(&clk_aclk_cored
.clk
);
538 aclk_corep
= clk_get_rate(&clk_aclk_corep
.clk
);
539 aclk_acp
= clk_get_rate(&clk_aclk_acp
.clk
);
540 pclk_acp
= clk_get_rate(&clk_pclk_acp
.clk
);
542 printk(KERN_INFO
"S5PV310: ARMCLK=%ld, COREM0=%ld, CORES=%ld\n"
543 "COREM1=%ld, PERI=%ld, DMC=%ld, CORED=%ld\n"
544 "COREP=%ld, ACLK_ACP=%ld, PCLK_ACP=%ld",
545 armclk
, aclk_corem0
, aclk_cores
, aclk_corem1
,
546 periphclk
, sclk_dmc
, aclk_cored
, aclk_corep
,
550 clk_h
.rate
= sclk_dmc
;
551 clk_p
.rate
= periphclk
;
553 for (ptr
= 0; ptr
< ARRAY_SIZE(clksrcs
); ptr
++)
554 s3c_set_clksrc(&clksrcs
[ptr
], true);
557 static struct clk
*clks
[] __initdata
= {
558 /* Nothing here yet */
561 void __init
s5pv310_register_clocks(void)
567 ret
= s3c24xx_register_clocks(clks
, ARRAY_SIZE(clks
));
569 printk(KERN_ERR
"Failed to register %u clocks\n", ret
);
571 for (ptr
= 0; ptr
< ARRAY_SIZE(sysclks
); ptr
++)
572 s3c_register_clksrc(sysclks
[ptr
], 1);
574 s3c_register_clksrc(clksrcs
, ARRAY_SIZE(clksrcs
));
575 s3c_register_clocks(init_clocks
, ARRAY_SIZE(init_clocks
));
577 clkp
= init_clocks_disable
;
578 for (ptr
= 0; ptr
< ARRAY_SIZE(init_clocks_disable
); ptr
++, clkp
++) {
579 ret
= s3c24xx_register_clock(clkp
);
581 printk(KERN_ERR
"Failed to register clock %s (%d)\n",
584 (clkp
->enable
)(clkp
, 0);