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