]> bbs.cooldavid.org Git - net-next-2.6.git/blob - arch/arm/mach-s5pv310/clock.c
ARM: S5PV310: Fix missed uart clocks
[net-next-2.6.git] / arch / arm / mach-s5pv310 / clock.c
1 /* linux/arch/arm/mach-s5pv310/clock.c
2  *
3  * Copyright (c) 2010 Samsung Electronics Co., Ltd.
4  *              http://www.samsung.com/
5  *
6  * S5PV310 - Clock support
7  *
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.
11 */
12
13 #include <linux/kernel.h>
14 #include <linux/err.h>
15 #include <linux/io.h>
16
17 #include <plat/cpu-freq.h>
18 #include <plat/clock.h>
19 #include <plat/cpu.h>
20 #include <plat/pll.h>
21 #include <plat/s5p-clock.h>
22 #include <plat/clock-clksrc.h>
23
24 #include <mach/map.h>
25 #include <mach/regs-clock.h>
26
27 static struct clk clk_sclk_hdmi27m = {
28         .name           = "sclk_hdmi27m",
29         .id             = -1,
30         .rate           = 27000000,
31 };
32
33 static int s5pv310_clk_ip_peril_ctrl(struct clk *clk, int enable)
34 {
35         return s5p_gatectrl(S5P_CLKGATE_IP_PERIL, clk, enable);
36 }
37
38 /* Core list of CMU_CPU side */
39
40 static struct clksrc_clk clk_mout_apll = {
41         .clk    = {
42                 .name           = "mout_apll",
43                 .id             = -1,
44         },
45         .sources        = &clk_src_apll,
46         .reg_src        = { .reg = S5P_CLKSRC_CPU, .shift = 0, .size = 1 },
47 };
48
49 static struct clksrc_clk clk_sclk_apll = {
50         .clk    = {
51                 .name           = "sclk_apll",
52                 .id             = -1,
53                 .parent         = &clk_mout_apll.clk,
54         },
55         .reg_div        = { .reg = S5P_CLKDIV_CPU, .shift = 24, .size = 3 },
56 };
57
58 static struct clksrc_clk clk_mout_epll = {
59         .clk    = {
60                 .name           = "mout_epll",
61                 .id             = -1,
62         },
63         .sources        = &clk_src_epll,
64         .reg_src        = { .reg = S5P_CLKSRC_TOP0, .shift = 4, .size = 1 },
65 };
66
67 static struct clksrc_clk clk_mout_mpll = {
68         .clk = {
69                 .name           = "mout_mpll",
70                 .id             = -1,
71         },
72         .sources        = &clk_src_mpll,
73         .reg_src        = { .reg = S5P_CLKSRC_CPU, .shift = 8, .size = 1 },
74 };
75
76 static struct clk *clkset_moutcore_list[] = {
77         [0] = &clk_sclk_apll.clk,
78         [1] = &clk_mout_mpll.clk,
79 };
80
81 static struct clksrc_sources clkset_moutcore = {
82         .sources        = clkset_moutcore_list,
83         .nr_sources     = ARRAY_SIZE(clkset_moutcore_list),
84 };
85
86 static struct clksrc_clk clk_moutcore = {
87         .clk    = {
88                 .name           = "moutcore",
89                 .id             = -1,
90         },
91         .sources        = &clkset_moutcore,
92         .reg_src        = { .reg = S5P_CLKSRC_CPU, .shift = 16, .size = 1 },
93 };
94
95 static struct clksrc_clk clk_coreclk = {
96         .clk    = {
97                 .name           = "core_clk",
98                 .id             = -1,
99                 .parent         = &clk_moutcore.clk,
100         },
101         .reg_div        = { .reg = S5P_CLKDIV_CPU, .shift = 0, .size = 3 },
102 };
103
104 static struct clksrc_clk clk_armclk = {
105         .clk    = {
106                 .name           = "armclk",
107                 .id             = -1,
108                 .parent         = &clk_coreclk.clk,
109         },
110 };
111
112 static struct clksrc_clk clk_aclk_corem0 = {
113         .clk    = {
114                 .name           = "aclk_corem0",
115                 .id             = -1,
116                 .parent         = &clk_coreclk.clk,
117         },
118         .reg_div        = { .reg = S5P_CLKDIV_CPU, .shift = 4, .size = 3 },
119 };
120
121 static struct clksrc_clk clk_aclk_cores = {
122         .clk    = {
123                 .name           = "aclk_cores",
124                 .id             = -1,
125                 .parent         = &clk_coreclk.clk,
126         },
127         .reg_div        = { .reg = S5P_CLKDIV_CPU, .shift = 4, .size = 3 },
128 };
129
130 static struct clksrc_clk clk_aclk_corem1 = {
131         .clk    = {
132                 .name           = "aclk_corem1",
133                 .id             = -1,
134                 .parent         = &clk_coreclk.clk,
135         },
136         .reg_div        = { .reg = S5P_CLKDIV_CPU, .shift = 8, .size = 3 },
137 };
138
139 static struct clksrc_clk clk_periphclk = {
140         .clk    = {
141                 .name           = "periphclk",
142                 .id             = -1,
143                 .parent         = &clk_coreclk.clk,
144         },
145         .reg_div        = { .reg = S5P_CLKDIV_CPU, .shift = 12, .size = 3 },
146 };
147
148 static struct clksrc_clk clk_atclk = {
149         .clk    = {
150                 .name           = "atclk",
151                 .id             = -1,
152                 .parent         = &clk_moutcore.clk,
153         },
154         .reg_div        = { .reg = S5P_CLKDIV_CPU, .shift = 16, .size = 3 },
155 };
156
157 static struct clksrc_clk clk_pclk_dbg = {
158         .clk    = {
159                 .name           = "pclk_dbg",
160                 .id             = -1,
161                 .parent         = &clk_atclk.clk,
162         },
163         .reg_div        = { .reg = S5P_CLKDIV_CPU, .shift = 20, .size = 3 },
164 };
165
166 /* Core list of CMU_CORE side */
167
168 static struct clk *clkset_corebus_list[] = {
169         [0] = &clk_mout_mpll.clk,
170         [1] = &clk_sclk_apll.clk,
171 };
172
173 static struct clksrc_sources clkset_mout_corebus = {
174         .sources        = clkset_corebus_list,
175         .nr_sources     = ARRAY_SIZE(clkset_corebus_list),
176 };
177
178 static struct clksrc_clk clk_mout_corebus = {
179         .clk    = {
180                 .name           = "mout_corebus",
181                 .id             = -1,
182         },
183         .sources        = &clkset_mout_corebus,
184         .reg_src        = { .reg = S5P_CLKSRC_CORE, .shift = 4, .size = 1 },
185 };
186
187 static struct clksrc_clk clk_sclk_dmc = {
188         .clk    = {
189                 .name           = "sclk_dmc",
190                 .id             = -1,
191                 .parent         = &clk_mout_corebus.clk,
192         },
193         .reg_div        = { .reg = S5P_CLKDIV_CORE0, .shift = 12, .size = 3 },
194 };
195
196 static struct clksrc_clk clk_aclk_cored = {
197         .clk    = {
198                 .name           = "aclk_cored",
199                 .id             = -1,
200                 .parent         = &clk_sclk_dmc.clk,
201         },
202         .reg_div        = { .reg = S5P_CLKDIV_CORE0, .shift = 16, .size = 3 },
203 };
204
205 static struct clksrc_clk clk_aclk_corep = {
206         .clk    = {
207                 .name           = "aclk_corep",
208                 .id             = -1,
209                 .parent         = &clk_aclk_cored.clk,
210         },
211         .reg_div        = { .reg = S5P_CLKDIV_CORE0, .shift = 20, .size = 3 },
212 };
213
214 static struct clksrc_clk clk_aclk_acp = {
215         .clk    = {
216                 .name           = "aclk_acp",
217                 .id             = -1,
218                 .parent         = &clk_mout_corebus.clk,
219         },
220         .reg_div        = { .reg = S5P_CLKDIV_CORE0, .shift = 0, .size = 3 },
221 };
222
223 static struct clksrc_clk clk_pclk_acp = {
224         .clk    = {
225                 .name           = "pclk_acp",
226                 .id             = -1,
227                 .parent         = &clk_aclk_acp.clk,
228         },
229         .reg_div        = { .reg = S5P_CLKDIV_CORE0, .shift = 4, .size = 3 },
230 };
231
232 /* Core list of CMU_TOP side */
233
234 static struct clk *clkset_aclk_top_list[] = {
235         [0] = &clk_mout_mpll.clk,
236         [1] = &clk_sclk_apll.clk,
237 };
238
239 static struct clksrc_sources clkset_aclk_200 = {
240         .sources        = clkset_aclk_top_list,
241         .nr_sources     = ARRAY_SIZE(clkset_aclk_top_list),
242 };
243
244 static struct clksrc_clk clk_aclk_200 = {
245         .clk    = {
246                 .name           = "aclk_200",
247                 .id             = -1,
248         },
249         .sources        = &clkset_aclk_200,
250         .reg_src        = { .reg = S5P_CLKSRC_TOP0, .shift = 12, .size = 1 },
251         .reg_div        = { .reg = S5P_CLKDIV_TOP, .shift = 0, .size = 3 },
252 };
253
254 static struct clksrc_sources clkset_aclk_100 = {
255         .sources        = clkset_aclk_top_list,
256         .nr_sources     = ARRAY_SIZE(clkset_aclk_top_list),
257 };
258
259 static struct clksrc_clk clk_aclk_100 = {
260         .clk    = {
261                 .name           = "aclk_100",
262                 .id             = -1,
263         },
264         .sources        = &clkset_aclk_100,
265         .reg_src        = { .reg = S5P_CLKSRC_TOP0, .shift = 16, .size = 1 },
266         .reg_div        = { .reg = S5P_CLKDIV_TOP, .shift = 4, .size = 4 },
267 };
268
269 static struct clksrc_sources clkset_aclk_160 = {
270         .sources        = clkset_aclk_top_list,
271         .nr_sources     = ARRAY_SIZE(clkset_aclk_top_list),
272 };
273
274 static struct clksrc_clk clk_aclk_160 = {
275         .clk    = {
276                 .name           = "aclk_160",
277                 .id             = -1,
278         },
279         .sources        = &clkset_aclk_160,
280         .reg_src        = { .reg = S5P_CLKSRC_TOP0, .shift = 20, .size = 1 },
281         .reg_div        = { .reg = S5P_CLKDIV_TOP, .shift = 8, .size = 3 },
282 };
283
284 static struct clksrc_sources clkset_aclk_133 = {
285         .sources        = clkset_aclk_top_list,
286         .nr_sources     = ARRAY_SIZE(clkset_aclk_top_list),
287 };
288
289 static struct clksrc_clk clk_aclk_133 = {
290         .clk    = {
291                 .name           = "aclk_133",
292                 .id             = -1,
293         },
294         .sources        = &clkset_aclk_133,
295         .reg_src        = { .reg = S5P_CLKSRC_TOP0, .shift = 24, .size = 1 },
296         .reg_div        = { .reg = S5P_CLKDIV_TOP, .shift = 12, .size = 3 },
297 };
298
299 static struct clk *clkset_vpllsrc_list[] = {
300         [0] = &clk_fin_vpll,
301         [1] = &clk_sclk_hdmi27m,
302 };
303
304 static struct clksrc_sources clkset_vpllsrc = {
305         .sources        = clkset_vpllsrc_list,
306         .nr_sources     = ARRAY_SIZE(clkset_vpllsrc_list),
307 };
308
309 static struct clksrc_clk clk_vpllsrc = {
310         .clk    = {
311                 .name           = "vpll_src",
312                 .id             = -1,
313         },
314         .sources        = &clkset_vpllsrc,
315         .reg_src        = { .reg = S5P_CLKSRC_TOP1, .shift = 0, .size = 1 },
316 };
317
318 static struct clk *clkset_sclk_vpll_list[] = {
319         [0] = &clk_vpllsrc.clk,
320         [1] = &clk_fout_vpll,
321 };
322
323 static struct clksrc_sources clkset_sclk_vpll = {
324         .sources        = clkset_sclk_vpll_list,
325         .nr_sources     = ARRAY_SIZE(clkset_sclk_vpll_list),
326 };
327
328 static struct clksrc_clk clk_sclk_vpll = {
329         .clk    = {
330                 .name           = "sclk_vpll",
331                 .id             = -1,
332         },
333         .sources        = &clkset_sclk_vpll,
334         .reg_src        = { .reg = S5P_CLKSRC_TOP0, .shift = 8, .size = 1 },
335 };
336
337 static struct clk init_clocks_disable[] = {
338         {
339                 .name           = "timers",
340                 .id             = -1,
341                 .parent         = &clk_aclk_100.clk,
342                 .enable         = s5pv310_clk_ip_peril_ctrl,
343                 .ctrlbit        = (1<<24),
344         }
345 };
346
347 static struct clk init_clocks[] = {
348         {
349                 .name           = "uart",
350                 .id             = 0,
351                 .enable         = s5pv310_clk_ip_peril_ctrl,
352                 .ctrlbit        = (1 << 0),
353         }, {
354                 .name           = "uart",
355                 .id             = 1,
356                 .enable         = s5pv310_clk_ip_peril_ctrl,
357                 .ctrlbit        = (1 << 1),
358         }, {
359                 .name           = "uart",
360                 .id             = 2,
361                 .enable         = s5pv310_clk_ip_peril_ctrl,
362                 .ctrlbit        = (1 << 2),
363         }, {
364                 .name           = "uart",
365                 .id             = 3,
366                 .enable         = s5pv310_clk_ip_peril_ctrl,
367                 .ctrlbit        = (1 << 3),
368         }, {
369                 .name           = "uart",
370                 .id             = 4,
371                 .enable         = s5pv310_clk_ip_peril_ctrl,
372                 .ctrlbit        = (1 << 4),
373         }, {
374                 .name           = "uart",
375                 .id             = 5,
376                 .enable         = s5pv310_clk_ip_peril_ctrl,
377                 .ctrlbit        = (1 << 5),
378         }
379 };
380
381 static struct clk *clkset_group_list[] = {
382         [0] = &clk_ext_xtal_mux,
383         [1] = &clk_xusbxti,
384         [2] = &clk_sclk_hdmi27m,
385         [6] = &clk_mout_mpll.clk,
386         [7] = &clk_mout_epll.clk,
387         [8] = &clk_sclk_vpll.clk,
388 };
389
390 static struct clksrc_sources clkset_group = {
391         .sources        = clkset_group_list,
392         .nr_sources     = ARRAY_SIZE(clkset_group_list),
393 };
394
395 static struct clksrc_clk clksrcs[] = {
396         {
397                 .clk    = {
398                         .name           = "uclk1",
399                         .id             = 0,
400                         .enable         = s5pv310_clk_ip_peril_ctrl,
401                         .ctrlbit        = (1 << 0),
402                 },
403                 .sources = &clkset_group,
404                 .reg_src = { .reg = S5P_CLKSRC_PERIL0, .shift = 0, .size = 4 },
405                 .reg_div = { .reg = S5P_CLKDIV_PERIL0, .shift = 0, .size = 4 },
406         }, {
407                 .clk            = {
408                         .name           = "uclk1",
409                         .id             = 1,
410                         .enable         = s5pv310_clk_ip_peril_ctrl,
411                         .ctrlbit        = (1 << 1),
412                 },
413                 .sources = &clkset_group,
414                 .reg_src = { .reg = S5P_CLKSRC_PERIL0, .shift = 4, .size = 4 },
415                 .reg_div = { .reg = S5P_CLKDIV_PERIL0, .shift = 4, .size = 4 },
416         }, {
417                 .clk            = {
418                         .name           = "uclk1",
419                         .id             = 2,
420                         .enable         = s5pv310_clk_ip_peril_ctrl,
421                         .ctrlbit        = (1 << 2),
422                 },
423                 .sources = &clkset_group,
424                 .reg_src = { .reg = S5P_CLKSRC_PERIL0, .shift = 8, .size = 4 },
425                 .reg_div = { .reg = S5P_CLKDIV_PERIL0, .shift = 8, .size = 4 },
426         }, {
427                 .clk            = {
428                         .name           = "uclk1",
429                         .id             = 3,
430                         .enable         = s5pv310_clk_ip_peril_ctrl,
431                         .ctrlbit        = (1 << 3),
432                 },
433                 .sources = &clkset_group,
434                 .reg_src = { .reg = S5P_CLKSRC_PERIL0, .shift = 12, .size = 4 },
435                 .reg_div = { .reg = S5P_CLKDIV_PERIL0, .shift = 12, .size = 4 },
436         }, {
437                 .clk            = {
438                         .name           = "sclk_pwm",
439                         .id             = -1,
440                         .enable         = s5pv310_clk_ip_peril_ctrl,
441                         .ctrlbit        = (1 << 24),
442                 },
443                 .sources = &clkset_group,
444                 .reg_src = { .reg = S5P_CLKSRC_PERIL0, .shift = 24, .size = 4 },
445                 .reg_div = { .reg = S5P_CLKDIV_PERIL3, .shift = 0, .size = 4 },
446         },
447 };
448
449 /* Clock initialization code */
450 static struct clksrc_clk *sysclks[] = {
451         &clk_mout_apll,
452         &clk_sclk_apll,
453         &clk_mout_epll,
454         &clk_mout_mpll,
455         &clk_moutcore,
456         &clk_coreclk,
457         &clk_armclk,
458         &clk_aclk_corem0,
459         &clk_aclk_cores,
460         &clk_aclk_corem1,
461         &clk_periphclk,
462         &clk_atclk,
463         &clk_pclk_dbg,
464         &clk_mout_corebus,
465         &clk_sclk_dmc,
466         &clk_aclk_cored,
467         &clk_aclk_corep,
468         &clk_aclk_acp,
469         &clk_pclk_acp,
470         &clk_vpllsrc,
471         &clk_sclk_vpll,
472         &clk_aclk_200,
473         &clk_aclk_100,
474         &clk_aclk_160,
475         &clk_aclk_133,
476 };
477
478 void __init_or_cpufreq s5pv310_setup_clocks(void)
479 {
480         struct clk *xtal_clk;
481         unsigned long apll;
482         unsigned long mpll;
483         unsigned long epll;
484         unsigned long vpll;
485         unsigned long vpllsrc;
486         unsigned long xtal;
487         unsigned long armclk;
488         unsigned long aclk_corem0;
489         unsigned long aclk_cores;
490         unsigned long aclk_corem1;
491         unsigned long periphclk;
492         unsigned long sclk_dmc;
493         unsigned long aclk_cored;
494         unsigned long aclk_corep;
495         unsigned long aclk_acp;
496         unsigned long pclk_acp;
497         unsigned int ptr;
498
499         printk(KERN_DEBUG "%s: registering clocks\n", __func__);
500
501         xtal_clk = clk_get(NULL, "xtal");
502         BUG_ON(IS_ERR(xtal_clk));
503
504         xtal = clk_get_rate(xtal_clk);
505         clk_put(xtal_clk);
506
507         printk(KERN_DEBUG "%s: xtal is %ld\n", __func__, xtal);
508
509         apll = s5p_get_pll45xx(xtal, __raw_readl(S5P_APLL_CON0), pll_4508);
510         mpll = s5p_get_pll45xx(xtal, __raw_readl(S5P_MPLL_CON0), pll_4508);
511         epll = s5p_get_pll46xx(xtal, __raw_readl(S5P_EPLL_CON0),
512                                 __raw_readl(S5P_EPLL_CON1), pll_4600);
513
514         vpllsrc = clk_get_rate(&clk_vpllsrc.clk);
515         vpll = s5p_get_pll46xx(vpllsrc, __raw_readl(S5P_VPLL_CON0),
516                                 __raw_readl(S5P_VPLL_CON1), pll_4650);
517
518         clk_fout_apll.rate = apll;
519         clk_fout_mpll.rate = mpll;
520         clk_fout_epll.rate = epll;
521         clk_fout_vpll.rate = vpll;
522
523         printk(KERN_INFO "S5PV310: PLL settings, A=%ld, M=%ld, E=%ld V=%ld",
524                         apll, mpll, epll, vpll);
525
526         armclk = clk_get_rate(&clk_armclk.clk);
527         aclk_corem0 = clk_get_rate(&clk_aclk_corem0.clk);
528         aclk_cores = clk_get_rate(&clk_aclk_cores.clk);
529         aclk_corem1 = clk_get_rate(&clk_aclk_corem1.clk);
530         periphclk = clk_get_rate(&clk_periphclk.clk);
531         sclk_dmc = clk_get_rate(&clk_sclk_dmc.clk);
532         aclk_cored = clk_get_rate(&clk_aclk_cored.clk);
533         aclk_corep = clk_get_rate(&clk_aclk_corep.clk);
534         aclk_acp = clk_get_rate(&clk_aclk_acp.clk);
535         pclk_acp = clk_get_rate(&clk_pclk_acp.clk);
536
537         printk(KERN_INFO "S5PV310: ARMCLK=%ld, COREM0=%ld, CORES=%ld\n"
538                          "COREM1=%ld, PERI=%ld, DMC=%ld, CORED=%ld\n"
539                          "COREP=%ld, ACLK_ACP=%ld, PCLK_ACP=%ld",
540                         armclk, aclk_corem0, aclk_cores, aclk_corem1,
541                         periphclk, sclk_dmc, aclk_cored, aclk_corep,
542                         aclk_acp, pclk_acp);
543
544         clk_f.rate = armclk;
545         clk_h.rate = sclk_dmc;
546         clk_p.rate = periphclk;
547
548         for (ptr = 0; ptr < ARRAY_SIZE(clksrcs); ptr++)
549                 s3c_set_clksrc(&clksrcs[ptr], true);
550 }
551
552 static struct clk *clks[] __initdata = {
553         /* Nothing here yet */
554 };
555
556 void __init s5pv310_register_clocks(void)
557 {
558         struct clk *clkp;
559         int ret;
560         int ptr;
561
562         ret = s3c24xx_register_clocks(clks, ARRAY_SIZE(clks));
563         if (ret > 0)
564                 printk(KERN_ERR "Failed to register %u clocks\n", ret);
565
566         for (ptr = 0; ptr < ARRAY_SIZE(sysclks); ptr++)
567                 s3c_register_clksrc(sysclks[ptr], 1);
568
569         s3c_register_clksrc(clksrcs, ARRAY_SIZE(clksrcs));
570         s3c_register_clocks(init_clocks, ARRAY_SIZE(init_clocks));
571
572         clkp = init_clocks_disable;
573         for (ptr = 0; ptr < ARRAY_SIZE(init_clocks_disable); ptr++, clkp++) {
574                 ret = s3c24xx_register_clock(clkp);
575                 if (ret < 0) {
576                         printk(KERN_ERR "Failed to register clock %s (%d)\n",
577                                clkp->name, ret);
578                 }
579                 (clkp->enable)(clkp, 0);
580         }
581
582         s3c_pwmclk_init();
583 }