blob: f89e71f50345b65cabadfeb1c2bf4c01cc83c277 [file] [log] [blame]
Ben Dookse4d06e32007-02-16 12:12:31 +01001/* linux/arch/arm/mach-s3c2443/clock.c
2 *
Ben Dooks9aa753c2010-01-30 09:19:59 +02003 * Copyright (c) 2007,2010 Simtec Electronics
Ben Dookse4d06e32007-02-16 12:12:31 +01004 * Ben Dooks <ben@simtec.co.uk>
5 *
6 * S3C2443 Clock control 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 as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21*/
22
23#include <linux/init.h>
24#include <linux/module.h>
25#include <linux/kernel.h>
26#include <linux/list.h>
27#include <linux/errno.h>
28#include <linux/err.h>
29#include <linux/sysdev.h>
30#include <linux/clk.h>
31#include <linux/mutex.h>
Ben Dookse4d06e32007-02-16 12:12:31 +010032#include <linux/serial_core.h>
Russell Kingfced80c2008-09-06 12:10:45 +010033#include <linux/io.h>
Ben Dookse4d06e32007-02-16 12:12:31 +010034
35#include <asm/mach/map.h>
36
Russell Kinga09e64f2008-08-05 16:14:15 +010037#include <mach/hardware.h>
Ben Dookse4d06e32007-02-16 12:12:31 +010038
Russell Kinga09e64f2008-08-05 16:14:15 +010039#include <mach/regs-s3c2443-clock.h>
Ben Dookse4d06e32007-02-16 12:12:31 +010040
Ben Dookse4253822008-10-21 14:06:38 +010041#include <plat/cpu-freq.h>
42
Ben Dooksa2b7ba92008-10-07 22:26:09 +010043#include <plat/s3c2443.h>
Ben Dooksd5120ae2008-10-07 23:09:51 +010044#include <plat/clock.h>
Ben Dooks9aa753c2010-01-30 09:19:59 +020045#include <plat/clock-clksrc.h>
Ben Dooksa2b7ba92008-10-07 22:26:09 +010046#include <plat/cpu.h>
Ben Dookse4d06e32007-02-16 12:12:31 +010047
48/* We currently have to assume that the system is running
49 * from the XTPll input, and that all ***REFCLKs are being
50 * fed from it, as we cannot read the state of OM[4] from
51 * software.
52 *
53 * It would be possible for each board initialisation to
54 * set the correct muxing at initialisation
55*/
56
Ben Dooks4ec07bb2010-01-30 15:02:58 +090057static int s3c2443_gate(void __iomem *reg, struct clk *clk, int enable)
Ben Dookse4d06e32007-02-16 12:12:31 +010058{
Ben Dooks4ec07bb2010-01-30 15:02:58 +090059 u32 ctrlbit = clk->ctrlbit;
60 u32 con = __raw_readl(reg);
Ben Dookse4d06e32007-02-16 12:12:31 +010061
62 if (enable)
Ben Dooks4ec07bb2010-01-30 15:02:58 +090063 con |= ctrlbit;
Ben Dookse4d06e32007-02-16 12:12:31 +010064 else
Ben Dooks4ec07bb2010-01-30 15:02:58 +090065 con &= ~ctrlbit;
Ben Dookse4d06e32007-02-16 12:12:31 +010066
Ben Dooks4ec07bb2010-01-30 15:02:58 +090067 __raw_writel(con, reg);
Ben Dookse4d06e32007-02-16 12:12:31 +010068 return 0;
69}
70
Ben Dooks4ec07bb2010-01-30 15:02:58 +090071static int s3c2443_clkcon_enable_h(struct clk *clk, int enable)
72{
73 return s3c2443_gate(S3C2443_HCLKCON, clk, enable);
74}
75
Ben Dookse4d06e32007-02-16 12:12:31 +010076static int s3c2443_clkcon_enable_p(struct clk *clk, int enable)
77{
Ben Dooks4ec07bb2010-01-30 15:02:58 +090078 return s3c2443_gate(S3C2443_PCLKCON, clk, enable);
Ben Dookse4d06e32007-02-16 12:12:31 +010079}
80
81static int s3c2443_clkcon_enable_s(struct clk *clk, int enable)
82{
Ben Dooks4ec07bb2010-01-30 15:02:58 +090083 return s3c2443_gate(S3C2443_SCLKCON, clk, enable);
Ben Dookse4d06e32007-02-16 12:12:31 +010084}
85
Ben Dooks9aa753c2010-01-30 09:19:59 +020086/* s3c2443_roundate_clksrc is close enough to s3c_roundate_clksrc */
Ben Dookse4d06e32007-02-16 12:12:31 +010087
88/* clock selections */
89
Ben Dookse4d06e32007-02-16 12:12:31 +010090static struct clk clk_mpllref = {
91 .name = "mpllref",
92 .parent = &clk_xtal,
93 .id = -1,
94};
95
96#if 0
97static struct clk clk_mpll = {
98 .name = "mpll",
99 .parent = &clk_mpllref,
100 .id = -1,
101};
102#endif
103
Ben Dookse4d06e32007-02-16 12:12:31 +0100104static struct clk clk_i2s_ext = {
105 .name = "i2s-ext",
106 .id = -1,
107};
108
Ben Dooks9aa753c2010-01-30 09:19:59 +0200109static struct clk *clk_epllref_sources[] = {
110 [0] = &clk_mpllref,
111 [1] = &clk_mpllref,
112 [2] = &clk_xtal,
113 [3] = &clk_ext,
114};
Ben Dookse4d06e32007-02-16 12:12:31 +0100115
Ben Dooks9aa753c2010-01-30 09:19:59 +0200116static struct clksrc_clk clk_epllref = {
117 .clk = {
118 .name = "epllref",
119 .id = -1,
Ben Dooksb3bf41b2009-12-01 01:24:37 +0000120 },
Ben Dooks9aa753c2010-01-30 09:19:59 +0200121 .sources = &(struct clksrc_sources) {
122 .sources = clk_epllref_sources,
123 .nr_sources = ARRAY_SIZE(clk_epllref_sources),
124 },
125 .reg_src = { .reg = S3C2443_CLKSRC, .size = 2, .shift = 7 },
Ben Dookse4d06e32007-02-16 12:12:31 +0100126};
127
128static unsigned long s3c2443_getrate_mdivclk(struct clk *clk)
129{
130 unsigned long parent_rate = clk_get_rate(clk->parent);
131 unsigned long div = __raw_readl(S3C2443_CLKDIV0);
132
133 div &= S3C2443_CLKDIV0_EXTDIV_MASK;
134 div >>= (S3C2443_CLKDIV0_EXTDIV_SHIFT-1); /* x2 */
135
136 return parent_rate / (div + 1);
137}
138
139static struct clk clk_mdivclk = {
140 .name = "mdivclk",
141 .parent = &clk_mpllref,
142 .id = -1,
Ben Dooksb3bf41b2009-12-01 01:24:37 +0000143 .ops = &(struct clk_ops) {
144 .get_rate = s3c2443_getrate_mdivclk,
145 },
Ben Dookse4d06e32007-02-16 12:12:31 +0100146};
147
Ben Dookse4d06e32007-02-16 12:12:31 +0100148static int s3c2443_setparent_msysclk(struct clk *clk, struct clk *parent)
149{
150 unsigned long clksrc = __raw_readl(S3C2443_CLKSRC);
151
152 clksrc &= ~(S3C2443_CLKSRC_MSYSCLK_MPLL |
153 S3C2443_CLKSRC_EXTCLK_DIV);
154
155 if (parent == &clk_mpll)
156 clksrc |= S3C2443_CLKSRC_MSYSCLK_MPLL;
157 else if (parent == &clk_mdivclk)
158 clksrc |= S3C2443_CLKSRC_EXTCLK_DIV;
159 else if (parent != &clk_mpllref)
160 return -EINVAL;
161
162 __raw_writel(clksrc, S3C2443_CLKSRC);
163 clk->parent = parent;
164
165 return 0;
166}
167
168static struct clk clk_msysclk = {
169 .name = "msysclk",
170 .parent = &clk_xtal,
171 .id = -1,
Ben Dooksb3bf41b2009-12-01 01:24:37 +0000172 .ops = &(struct clk_ops) {
173 .set_parent = s3c2443_setparent_msysclk,
174 },
Ben Dookse4d06e32007-02-16 12:12:31 +0100175};
176
Ben Dooksba7622a2008-07-07 18:12:39 +0100177/* armdiv
178 *
179 * this clock is sourced from msysclk and can have a number of
180 * divider values applied to it to then be fed into armclk.
181*/
182
183static struct clk clk_armdiv = {
184 .name = "armdiv",
185 .id = -1,
186 .parent = &clk_msysclk,
187};
188
189/* armclk
190 *
191 * this is the clock fed into the ARM core itself, either from
192 * armdiv or from hclk.
193 */
194
195static int s3c2443_setparent_armclk(struct clk *clk, struct clk *parent)
196{
197 unsigned long clkdiv0;
198
199 clkdiv0 = __raw_readl(S3C2443_CLKDIV0);
200
201 if (parent == &clk_armdiv)
202 clkdiv0 &= ~S3C2443_CLKDIV0_DVS;
203 else if (parent == &clk_h)
204 clkdiv0 |= S3C2443_CLKDIV0_DVS;
205 else
206 return -EINVAL;
207
208 __raw_writel(clkdiv0, S3C2443_CLKDIV0);
209 return 0;
210}
211
212static struct clk clk_arm = {
213 .name = "armclk",
214 .id = -1,
Ben Dooksb3bf41b2009-12-01 01:24:37 +0000215 .ops = &(struct clk_ops) {
216 .set_parent = s3c2443_setparent_armclk,
217 },
Ben Dooksba7622a2008-07-07 18:12:39 +0100218};
Ben Dookse4d06e32007-02-16 12:12:31 +0100219
220/* esysclk
221 *
222 * this is sourced from either the EPLL or the EPLLref clock
223*/
224
225static int s3c2443_setparent_esysclk(struct clk *clk, struct clk *parent)
226{
227 unsigned long clksrc = __raw_readl(S3C2443_CLKSRC);
228
229 if (parent == &clk_epll)
230 clksrc |= S3C2443_CLKSRC_ESYSCLK_EPLL;
Ben Dooks9aa753c2010-01-30 09:19:59 +0200231 else if (parent == &clk_epllref.clk)
Ben Dookse4d06e32007-02-16 12:12:31 +0100232 clksrc &= ~S3C2443_CLKSRC_ESYSCLK_EPLL;
233 else
234 return -EINVAL;
235
236 __raw_writel(clksrc, S3C2443_CLKSRC);
237 clk->parent = parent;
238
239 return 0;
240}
241
242static struct clk clk_esysclk = {
243 .name = "esysclk",
244 .parent = &clk_epll,
245 .id = -1,
Ben Dooksb3bf41b2009-12-01 01:24:37 +0000246 .ops = &(struct clk_ops) {
247 .set_parent = s3c2443_setparent_esysclk,
248 },
Ben Dookse4d06e32007-02-16 12:12:31 +0100249};
250
251/* uartclk
252 *
253 * UART baud-rate clock sourced from esysclk via a divisor
254*/
255
Ben Dooks9aa753c2010-01-30 09:19:59 +0200256static struct clksrc_clk clk_uart = {
257 .clk = {
258 .name = "uartclk",
259 .id = -1,
260 .parent = &clk_esysclk,
Ben Dooksb3bf41b2009-12-01 01:24:37 +0000261 },
Ben Dooks9aa753c2010-01-30 09:19:59 +0200262 .reg_div = { .reg = S3C2443_CLKDIV1, .size = 4, .shift = 8 },
Ben Dookse4d06e32007-02-16 12:12:31 +0100263};
264
Ben Dooks9aa753c2010-01-30 09:19:59 +0200265
Ben Dookse4d06e32007-02-16 12:12:31 +0100266/* hsspi
267 *
268 * high-speed spi clock, sourced from esysclk
269*/
270
Ben Dooks9aa753c2010-01-30 09:19:59 +0200271static struct clksrc_clk clk_hsspi = {
272 .clk = {
273 .name = "hsspi",
274 .id = -1,
275 .parent = &clk_esysclk,
276 .ctrlbit = S3C2443_SCLKCON_HSSPICLK,
277 .enable = s3c2443_clkcon_enable_s,
Ben Dooksb3bf41b2009-12-01 01:24:37 +0000278 },
Ben Dooks9aa753c2010-01-30 09:19:59 +0200279 .reg_div = { .reg = S3C2443_CLKDIV1, .size = 2, .shift = 4 },
Ben Dookse4d06e32007-02-16 12:12:31 +0100280};
281
282/* usbhost
283 *
284 * usb host bus-clock, usually 48MHz to provide USB bus clock timing
285*/
286
Ben Dooks9aa753c2010-01-30 09:19:59 +0200287static struct clksrc_clk clk_usb_bus_host = {
288 .clk = {
289 .name = "usb-bus-host-parent",
290 .id = -1,
291 .parent = &clk_esysclk,
292 .ctrlbit = S3C2443_SCLKCON_USBHOST,
293 .enable = s3c2443_clkcon_enable_s,
Ben Dooksb3bf41b2009-12-01 01:24:37 +0000294 },
Ben Dooks9aa753c2010-01-30 09:19:59 +0200295 .reg_div = { .reg = S3C2443_CLKDIV1, .size = 2, .shift = 4 },
Ben Dookse4d06e32007-02-16 12:12:31 +0100296};
297
298/* clk_hsmcc_div
299 *
300 * this clock is sourced from epll, and is fed through a divider,
301 * to a mux controlled by sclkcon where either it or a extclk can
302 * be fed to the hsmmc block
303*/
304
Ben Dooks9aa753c2010-01-30 09:19:59 +0200305static struct clksrc_clk clk_hsmmc_div = {
306 .clk = {
307 .name = "hsmmc-div",
308 .id = -1,
309 .parent = &clk_esysclk,
Ben Dooksb3bf41b2009-12-01 01:24:37 +0000310 },
Ben Dooks9aa753c2010-01-30 09:19:59 +0200311 .reg_div = { .reg = S3C2443_CLKDIV1, .size = 2, .shift = 6 },
Ben Dookse4d06e32007-02-16 12:12:31 +0100312};
313
314static int s3c2443_setparent_hsmmc(struct clk *clk, struct clk *parent)
315{
316 unsigned long clksrc = __raw_readl(S3C2443_SCLKCON);
317
318 clksrc &= ~(S3C2443_SCLKCON_HSMMCCLK_EXT |
319 S3C2443_SCLKCON_HSMMCCLK_EPLL);
320
321 if (parent == &clk_epll)
322 clksrc |= S3C2443_SCLKCON_HSMMCCLK_EPLL;
323 else if (parent == &clk_ext)
324 clksrc |= S3C2443_SCLKCON_HSMMCCLK_EXT;
325 else
326 return -EINVAL;
327
328 if (clk->usage > 0) {
329 __raw_writel(clksrc, S3C2443_SCLKCON);
330 }
331
332 clk->parent = parent;
333 return 0;
334}
335
336static int s3c2443_enable_hsmmc(struct clk *clk, int enable)
337{
338 return s3c2443_setparent_hsmmc(clk, clk->parent);
339}
340
341static struct clk clk_hsmmc = {
342 .name = "hsmmc-if",
343 .id = -1,
Ben Dooks9aa753c2010-01-30 09:19:59 +0200344 .parent = &clk_hsmmc_div.clk,
Ben Dookse4d06e32007-02-16 12:12:31 +0100345 .enable = s3c2443_enable_hsmmc,
Ben Dooksb3bf41b2009-12-01 01:24:37 +0000346 .ops = &(struct clk_ops) {
347 .set_parent = s3c2443_setparent_hsmmc,
348 },
Ben Dookse4d06e32007-02-16 12:12:31 +0100349};
350
351/* i2s_eplldiv
352 *
Ben Dooks9aa753c2010-01-30 09:19:59 +0200353 * This clock is the output from the I2S divisor of ESYSCLK, and is seperate
354 * from the mux that comes after it (cannot merge into one single clock)
Ben Dookse4d06e32007-02-16 12:12:31 +0100355*/
356
Ben Dooks9aa753c2010-01-30 09:19:59 +0200357static struct clksrc_clk clk_i2s_eplldiv = {
358 .clk = {
359 .name = "i2s-eplldiv",
360 .id = -1,
361 .parent = &clk_esysclk,
Ben Dooksb3bf41b2009-12-01 01:24:37 +0000362 },
Ben Dooks9aa753c2010-01-30 09:19:59 +0200363 .reg_div = { .reg = S3C2443_CLKDIV1, .size = 4, .shift = 12, },
Ben Dookse4d06e32007-02-16 12:12:31 +0100364};
365
366/* i2s-ref
367 *
368 * i2s bus reference clock, selectable from external, esysclk or epllref
Ben Dooks9aa753c2010-01-30 09:19:59 +0200369 *
370 * Note, this used to be two clocks, but was compressed into one.
Ben Dookse4d06e32007-02-16 12:12:31 +0100371*/
372
Ben Dooks9aa753c2010-01-30 09:19:59 +0200373struct clk *clk_i2s_srclist[] = {
374 [0] = &clk_i2s_eplldiv.clk,
375 [1] = &clk_i2s_ext,
376 [2] = &clk_epllref.clk,
377 [3] = &clk_epllref.clk,
378};
Ben Dookse4d06e32007-02-16 12:12:31 +0100379
Ben Dooks9aa753c2010-01-30 09:19:59 +0200380static struct clksrc_clk clk_i2s = {
381 .clk = {
382 .name = "i2s-if",
383 .id = -1,
384 .ctrlbit = S3C2443_SCLKCON_I2SCLK,
385 .enable = s3c2443_clkcon_enable_s,
Ben Dookse4d06e32007-02-16 12:12:31 +0100386
Ben Dooksb3bf41b2009-12-01 01:24:37 +0000387 },
Ben Dooks9aa753c2010-01-30 09:19:59 +0200388 .sources = &(struct clksrc_sources) {
389 .sources = clk_i2s_srclist,
390 .nr_sources = ARRAY_SIZE(clk_i2s_srclist),
391 },
392 .reg_src = { .reg = S3C2443_CLKSRC, .size = 2, .shift = 14 },
Ben Dookse4d06e32007-02-16 12:12:31 +0100393};
394
395/* cam-if
396 *
397 * camera interface bus-clock, divided down from esysclk
398*/
399
Ben Dooks9aa753c2010-01-30 09:19:59 +0200400static struct clksrc_clk clk_cam = {
401 .clk = {
402 .name = "camif-upll", /* same as 2440 name */
403 .id = -1,
404 .parent = &clk_esysclk,
405 .ctrlbit = S3C2443_SCLKCON_CAMCLK,
406 .enable = s3c2443_clkcon_enable_s,
Ben Dooksb3bf41b2009-12-01 01:24:37 +0000407 },
Ben Dooks9aa753c2010-01-30 09:19:59 +0200408 .reg_div = { .reg = S3C2443_CLKDIV1, .size = 4, .shift = 26 },
Ben Dookse4d06e32007-02-16 12:12:31 +0100409};
410
411/* display-if
412 *
413 * display interface clock, divided from esysclk
414*/
415
Ben Dooks9aa753c2010-01-30 09:19:59 +0200416static struct clksrc_clk clk_display = {
417 .clk = {
418 .name = "display-if",
419 .id = -1,
420 .parent = &clk_esysclk,
421 .ctrlbit = S3C2443_SCLKCON_DISPCLK,
422 .enable = s3c2443_clkcon_enable_s,
Ben Dooksb3bf41b2009-12-01 01:24:37 +0000423 },
Ben Dooks9aa753c2010-01-30 09:19:59 +0200424 .reg_div = { .reg = S3C2443_CLKDIV1, .size = 8, .shift = 16 },
Ben Dookse4d06e32007-02-16 12:12:31 +0100425};
426
Ben Dooks2e16c272008-07-07 18:12:40 +0100427/* prediv
428 *
429 * this divides the msysclk down to pass to h/p/etc.
430 */
431
432static unsigned long s3c2443_prediv_getrate(struct clk *clk)
433{
434 unsigned long rate = clk_get_rate(clk->parent);
435 unsigned long clkdiv0 = __raw_readl(S3C2443_CLKDIV0);
436
437 clkdiv0 &= S3C2443_CLKDIV0_PREDIV_MASK;
438 clkdiv0 >>= S3C2443_CLKDIV0_PREDIV_SHIFT;
439
440 return rate / (clkdiv0 + 1);
441}
442
443static struct clk clk_prediv = {
444 .name = "prediv",
445 .id = -1,
446 .parent = &clk_msysclk,
Ben Dooksb3bf41b2009-12-01 01:24:37 +0000447 .ops = &(struct clk_ops) {
448 .get_rate = s3c2443_prediv_getrate,
449 },
Ben Dooks2e16c272008-07-07 18:12:40 +0100450};
451
Ben Dookse4d06e32007-02-16 12:12:31 +0100452/* standard clock definitions */
453
454static struct clk init_clocks_disable[] = {
455 {
456 .name = "nand",
457 .id = -1,
458 .parent = &clk_h,
459 }, {
460 .name = "sdi",
461 .id = -1,
462 .parent = &clk_p,
463 .enable = s3c2443_clkcon_enable_p,
464 .ctrlbit = S3C2443_PCLKCON_SDI,
465 }, {
466 .name = "adc",
467 .id = -1,
468 .parent = &clk_p,
469 .enable = s3c2443_clkcon_enable_p,
470 .ctrlbit = S3C2443_PCLKCON_ADC,
471 }, {
472 .name = "i2c",
473 .id = -1,
474 .parent = &clk_p,
475 .enable = s3c2443_clkcon_enable_p,
476 .ctrlbit = S3C2443_PCLKCON_IIC,
477 }, {
478 .name = "iis",
479 .id = -1,
480 .parent = &clk_p,
481 .enable = s3c2443_clkcon_enable_p,
482 .ctrlbit = S3C2443_PCLKCON_IIS,
483 }, {
484 .name = "spi",
485 .id = 0,
486 .parent = &clk_p,
487 .enable = s3c2443_clkcon_enable_p,
488 .ctrlbit = S3C2443_PCLKCON_SPI0,
489 }, {
490 .name = "spi",
491 .id = 1,
492 .parent = &clk_p,
493 .enable = s3c2443_clkcon_enable_p,
494 .ctrlbit = S3C2443_PCLKCON_SPI1,
495 }
496};
497
498static struct clk init_clocks[] = {
499 {
500 .name = "dma",
501 .id = 0,
502 .parent = &clk_h,
503 .enable = s3c2443_clkcon_enable_h,
504 .ctrlbit = S3C2443_HCLKCON_DMA0,
505 }, {
506 .name = "dma",
507 .id = 1,
508 .parent = &clk_h,
509 .enable = s3c2443_clkcon_enable_h,
510 .ctrlbit = S3C2443_HCLKCON_DMA1,
511 }, {
512 .name = "dma",
513 .id = 2,
514 .parent = &clk_h,
515 .enable = s3c2443_clkcon_enable_h,
516 .ctrlbit = S3C2443_HCLKCON_DMA2,
517 }, {
518 .name = "dma",
519 .id = 3,
520 .parent = &clk_h,
521 .enable = s3c2443_clkcon_enable_h,
522 .ctrlbit = S3C2443_HCLKCON_DMA3,
523 }, {
524 .name = "dma",
525 .id = 4,
526 .parent = &clk_h,
527 .enable = s3c2443_clkcon_enable_h,
528 .ctrlbit = S3C2443_HCLKCON_DMA4,
529 }, {
530 .name = "dma",
531 .id = 5,
532 .parent = &clk_h,
533 .enable = s3c2443_clkcon_enable_h,
534 .ctrlbit = S3C2443_HCLKCON_DMA5,
535 }, {
536 .name = "lcd",
537 .id = -1,
538 .parent = &clk_h,
539 .enable = s3c2443_clkcon_enable_h,
540 .ctrlbit = S3C2443_HCLKCON_LCDC,
541 }, {
542 .name = "gpio",
543 .id = -1,
544 .parent = &clk_p,
545 .enable = s3c2443_clkcon_enable_p,
546 .ctrlbit = S3C2443_PCLKCON_GPIO,
547 }, {
548 .name = "usb-host",
549 .id = -1,
550 .parent = &clk_h,
551 .enable = s3c2443_clkcon_enable_h,
552 .ctrlbit = S3C2443_HCLKCON_USBH,
553 }, {
554 .name = "usb-device",
555 .id = -1,
556 .parent = &clk_h,
557 .enable = s3c2443_clkcon_enable_h,
558 .ctrlbit = S3C2443_HCLKCON_USBD,
559 }, {
Ben Dooks67364332007-05-20 17:17:32 +0100560 .name = "hsmmc",
561 .id = -1,
562 .parent = &clk_h,
563 .enable = s3c2443_clkcon_enable_h,
564 .ctrlbit = S3C2443_HCLKCON_HSMMC,
565 }, {
566 .name = "cfc",
567 .id = -1,
568 .parent = &clk_h,
569 .enable = s3c2443_clkcon_enable_h,
570 .ctrlbit = S3C2443_HCLKCON_CFC,
Ben Dooks67364332007-05-20 17:17:32 +0100571 }, {
572 .name = "ssmc",
573 .id = -1,
574 .parent = &clk_h,
575 .enable = s3c2443_clkcon_enable_h,
576 .ctrlbit = S3C2443_HCLKCON_SSMC,
577 }, {
Ben Dookse4d06e32007-02-16 12:12:31 +0100578 .name = "timers",
579 .id = -1,
580 .parent = &clk_p,
581 .enable = s3c2443_clkcon_enable_p,
582 .ctrlbit = S3C2443_PCLKCON_PWMT,
583 }, {
584 .name = "uart",
585 .id = 0,
586 .parent = &clk_p,
587 .enable = s3c2443_clkcon_enable_p,
588 .ctrlbit = S3C2443_PCLKCON_UART0,
589 }, {
590 .name = "uart",
591 .id = 1,
592 .parent = &clk_p,
593 .enable = s3c2443_clkcon_enable_p,
594 .ctrlbit = S3C2443_PCLKCON_UART1,
595 }, {
596 .name = "uart",
597 .id = 2,
598 .parent = &clk_p,
599 .enable = s3c2443_clkcon_enable_p,
600 .ctrlbit = S3C2443_PCLKCON_UART2,
601 }, {
602 .name = "uart",
603 .id = 3,
604 .parent = &clk_p,
605 .enable = s3c2443_clkcon_enable_p,
606 .ctrlbit = S3C2443_PCLKCON_UART3,
607 }, {
608 .name = "rtc",
609 .id = -1,
610 .parent = &clk_p,
611 .enable = s3c2443_clkcon_enable_p,
612 .ctrlbit = S3C2443_PCLKCON_RTC,
613 }, {
614 .name = "watchdog",
615 .id = -1,
616 .parent = &clk_p,
617 .ctrlbit = S3C2443_PCLKCON_WDT,
618 }, {
619 .name = "usb-bus-host",
620 .id = -1,
Ben Dooks9aa753c2010-01-30 09:19:59 +0200621 .parent = &clk_usb_bus_host.clk,
Ben Dooks67364332007-05-20 17:17:32 +0100622 }, {
623 .name = "ac97",
Graeme Gregoryb8b69702007-05-09 15:55:24 +0100624 .id = -1,
625 .parent = &clk_p,
626 .ctrlbit = S3C2443_PCLKCON_AC97,
Ben Dookse4d06e32007-02-16 12:12:31 +0100627 }
628};
629
630/* clocks to add where we need to check their parentage */
631
632/* s3c2443_clk_initparents
633 *
634 * Initialise the parents for the clocks that we get at start-time
635*/
636
637static int __init clk_init_set_parent(struct clk *clk, struct clk *parent)
638{
639 printk(KERN_DEBUG "clock %s: parent %s\n", clk->name, parent->name);
640 return clk_set_parent(clk, parent);
641}
642
Ben Dooks9aa753c2010-01-30 09:19:59 +0200643static struct clksrc_clk __initdata *init_list[] = {
644 &clk_epllref, /* should be first */
645 &clk_i2s_eplldiv,
646 &clk_i2s,
647 &clk_cam,
648 &clk_uart,
649 &clk_display,
650 &clk_hsmmc_div,
651 &clk_usb_bus_host,
652};
653
Ben Dookse4d06e32007-02-16 12:12:31 +0100654static void __init s3c2443_clk_initparents(void)
655{
656 unsigned long clksrc = __raw_readl(S3C2443_CLKSRC);
657 struct clk *parent;
Ben Dooks9aa753c2010-01-30 09:19:59 +0200658 int ptr;
Ben Dookse4d06e32007-02-16 12:12:31 +0100659
660 /* esysclk source */
661
662 parent = (clksrc & S3C2443_CLKSRC_ESYSCLK_EPLL) ?
Ben Dooks9aa753c2010-01-30 09:19:59 +0200663 &clk_epll : &clk_epllref.clk;
Ben Dookse4d06e32007-02-16 12:12:31 +0100664
665 clk_init_set_parent(&clk_esysclk, parent);
666
667 /* msysclk source */
668
669 if (clksrc & S3C2443_CLKSRC_MSYSCLK_MPLL) {
670 parent = &clk_mpll;
671 } else {
672 parent = (clksrc & S3C2443_CLKSRC_EXTCLK_DIV) ?
673 &clk_mdivclk : &clk_mpllref;
674 }
675
676 clk_init_set_parent(&clk_msysclk, parent);
Ben Dooksba7622a2008-07-07 18:12:39 +0100677
678 /* arm */
679
680 if (__raw_readl(S3C2443_CLKDIV0) & S3C2443_CLKDIV0_DVS)
681 parent = &clk_h;
682 else
683 parent = &clk_armdiv;
684
685 clk_init_set_parent(&clk_arm, parent);
Ben Dooks9aa753c2010-01-30 09:19:59 +0200686
687 for (ptr = 0; ptr < ARRAY_SIZE(init_list); ptr++)
688 s3c_set_clksrc(init_list[ptr], false);
Ben Dookse4d06e32007-02-16 12:12:31 +0100689}
690
691/* armdiv divisor table */
692
693static unsigned int armdiv[16] = {
694 [S3C2443_CLKDIV0_ARMDIV_1 >> S3C2443_CLKDIV0_ARMDIV_SHIFT] = 1,
695 [S3C2443_CLKDIV0_ARMDIV_2 >> S3C2443_CLKDIV0_ARMDIV_SHIFT] = 2,
696 [S3C2443_CLKDIV0_ARMDIV_3 >> S3C2443_CLKDIV0_ARMDIV_SHIFT] = 3,
697 [S3C2443_CLKDIV0_ARMDIV_4 >> S3C2443_CLKDIV0_ARMDIV_SHIFT] = 4,
698 [S3C2443_CLKDIV0_ARMDIV_6 >> S3C2443_CLKDIV0_ARMDIV_SHIFT] = 6,
699 [S3C2443_CLKDIV0_ARMDIV_8 >> S3C2443_CLKDIV0_ARMDIV_SHIFT] = 8,
700 [S3C2443_CLKDIV0_ARMDIV_12 >> S3C2443_CLKDIV0_ARMDIV_SHIFT] = 12,
701 [S3C2443_CLKDIV0_ARMDIV_16 >> S3C2443_CLKDIV0_ARMDIV_SHIFT] = 16,
702};
703
704static inline unsigned int s3c2443_fclk_div(unsigned long clkcon0)
705{
706 clkcon0 &= S3C2443_CLKDIV0_ARMDIV_MASK;
707
708 return armdiv[clkcon0 >> S3C2443_CLKDIV0_ARMDIV_SHIFT];
709}
710
Ben Dooks2e16c272008-07-07 18:12:40 +0100711static inline unsigned long s3c2443_get_hdiv(unsigned long clkcon0)
Ben Dookse4d06e32007-02-16 12:12:31 +0100712{
Ben Dooks2e16c272008-07-07 18:12:40 +0100713 clkcon0 &= S3C2443_CLKDIV0_HCLKDIV_MASK;
Ben Dookse4d06e32007-02-16 12:12:31 +0100714
715 return clkcon0 + 1;
716}
717
718/* clocks to add straight away */
719
Ben Dooks9aa753c2010-01-30 09:19:59 +0200720static struct clksrc_clk *clksrcs[] __initdata = {
Ben Dookse4d06e32007-02-16 12:12:31 +0100721 &clk_usb_bus_host,
Ben Dookse4d06e32007-02-16 12:12:31 +0100722 &clk_epllref,
Ben Dookse4d06e32007-02-16 12:12:31 +0100723 &clk_uart,
724 &clk_display,
725 &clk_cam,
726 &clk_i2s_eplldiv,
727 &clk_i2s,
728 &clk_hsspi,
729 &clk_hsmmc_div,
Ben Dooks9aa753c2010-01-30 09:19:59 +0200730};
731
732static struct clk *clks[] __initdata = {
733 &clk_ext,
734 &clk_epll,
735 &clk_usb_bus,
736 &clk_esysclk,
737 &clk_mpllref,
738 &clk_msysclk,
Ben Dookse4d06e32007-02-16 12:12:31 +0100739 &clk_hsmmc,
Ben Dooksba7622a2008-07-07 18:12:39 +0100740 &clk_armdiv,
741 &clk_arm,
Ben Dooks2e16c272008-07-07 18:12:40 +0100742 &clk_prediv,
Ben Dookse4d06e32007-02-16 12:12:31 +0100743};
744
Ben Dookse4253822008-10-21 14:06:38 +0100745void __init_or_cpufreq s3c2443_setup_clocks(void)
Ben Dookse4d06e32007-02-16 12:12:31 +0100746{
Ben Dookse4d06e32007-02-16 12:12:31 +0100747 unsigned long mpllcon = __raw_readl(S3C2443_MPLLCON);
748 unsigned long clkdiv0 = __raw_readl(S3C2443_CLKDIV0);
Ben Dookse4253822008-10-21 14:06:38 +0100749 struct clk *xtal_clk;
750 unsigned long xtal;
Ben Dookse4d06e32007-02-16 12:12:31 +0100751 unsigned long pll;
752 unsigned long fclk;
753 unsigned long hclk;
754 unsigned long pclk;
Ben Dookse4d06e32007-02-16 12:12:31 +0100755
Ben Dookse4253822008-10-21 14:06:38 +0100756 xtal_clk = clk_get(NULL, "xtal");
757 xtal = clk_get_rate(xtal_clk);
758 clk_put(xtal_clk);
Ben Dooks2e16c272008-07-07 18:12:40 +0100759
Ben Dookse4d06e32007-02-16 12:12:31 +0100760 pll = s3c2443_get_mpll(mpllcon, xtal);
Ben Dooks2e16c272008-07-07 18:12:40 +0100761 clk_msysclk.rate = pll;
Ben Dookse4d06e32007-02-16 12:12:31 +0100762
763 fclk = pll / s3c2443_fclk_div(clkdiv0);
Ben Dooks2e16c272008-07-07 18:12:40 +0100764 hclk = s3c2443_prediv_getrate(&clk_prediv);
Ben Dooks5c378662008-10-16 16:46:09 +0100765 hclk /= s3c2443_get_hdiv(clkdiv0);
Ben Dookse4d06e32007-02-16 12:12:31 +0100766 pclk = hclk / ((clkdiv0 & S3C2443_CLKDIV0_HALF_PCLK) ? 2 : 1);
767
Ben Dookse4253822008-10-21 14:06:38 +0100768 s3c24xx_setup_clocks(fclk, hclk, pclk);
Ben Dookse4d06e32007-02-16 12:12:31 +0100769
770 printk("S3C2443: mpll %s %ld.%03ld MHz, cpu %ld.%03ld MHz, mem %ld.%03ld MHz, pclk %ld.%03ld MHz\n",
771 (mpllcon & S3C2443_PLLCON_OFF) ? "off":"on",
772 print_mhz(pll), print_mhz(fclk),
773 print_mhz(hclk), print_mhz(pclk));
774
Ben Dookse4253822008-10-21 14:06:38 +0100775 s3c24xx_setup_clocks(fclk, hclk, pclk);
776}
777
778void __init s3c2443_init_clocks(int xtal)
779{
780 struct clk *clkp;
781 unsigned long epllcon = __raw_readl(S3C2443_EPLLCON);
782 int ret;
783 int ptr;
784
785 /* s3c2443 parents h and p clocks from prediv */
786 clk_h.parent = &clk_prediv;
787 clk_p.parent = &clk_prediv;
788
789 s3c24xx_register_baseclocks(xtal);
790 s3c2443_setup_clocks();
Ben Dookse4d06e32007-02-16 12:12:31 +0100791 s3c2443_clk_initparents();
792
793 for (ptr = 0; ptr < ARRAY_SIZE(clks); ptr++) {
794 clkp = clks[ptr];
795
796 ret = s3c24xx_register_clock(clkp);
797 if (ret < 0) {
798 printk(KERN_ERR "Failed to register clock %s (%d)\n",
799 clkp->name, ret);
800 }
801 }
802
Ben Dooks9aa753c2010-01-30 09:19:59 +0200803 for (ptr = 0; ptr < ARRAY_SIZE(clksrcs); ptr++)
804 s3c_register_clksrc(clksrcs[ptr], 1);
805
Ben Dookse4d06e32007-02-16 12:12:31 +0100806 clk_epll.rate = s3c2443_get_epll(epllcon, xtal);
Ben Dooks9aa753c2010-01-30 09:19:59 +0200807 clk_epll.parent = &clk_epllref.clk;
808 clk_usb_bus.parent = &clk_usb_bus_host.clk;
Ben Dookse4d06e32007-02-16 12:12:31 +0100809
810 /* ensure usb bus clock is within correct rate of 48MHz */
811
Ben Dooks9aa753c2010-01-30 09:19:59 +0200812 if (clk_get_rate(&clk_usb_bus_host.clk) != (48 * 1000 * 1000)) {
Ben Dookse4d06e32007-02-16 12:12:31 +0100813 printk(KERN_INFO "Warning: USB host bus not at 48MHz\n");
Ben Dooks9aa753c2010-01-30 09:19:59 +0200814 clk_set_rate(&clk_usb_bus_host.clk, 48*1000*1000);
Ben Dookse4d06e32007-02-16 12:12:31 +0100815 }
816
817 printk("S3C2443: epll %s %ld.%03ld MHz, usb-bus %ld.%03ld MHz\n",
818 (epllcon & S3C2443_PLLCON_OFF) ? "off":"on",
819 print_mhz(clk_get_rate(&clk_epll)),
820 print_mhz(clk_get_rate(&clk_usb_bus)));
821
822 /* register clocks from clock array */
823
Ben Dooks1d9f13c2010-01-06 01:21:38 +0900824 s3c_register_clocks(init_clocks, ARRAY_SIZE(init_clocks));
Ben Dookse4d06e32007-02-16 12:12:31 +0100825
826 /* We must be careful disabling the clocks we are not intending to
Robert P. J. Day3a4fa0a2007-10-19 23:10:43 +0200827 * be using at boot time, as subsystems such as the LCD which do
Ben Dookse4d06e32007-02-16 12:12:31 +0100828 * their own DMA requests to the bus can cause the system to lockup
829 * if they where in the middle of requesting bus access.
830 *
831 * Disabling the LCD clock if the LCD is active is very dangerous,
832 * and therefore the bootloader should be careful to not enable
833 * the LCD clock if it is not needed.
834 */
835
836 /* install (and disable) the clocks we do not need immediately */
837
838 clkp = init_clocks_disable;
839 for (ptr = 0; ptr < ARRAY_SIZE(init_clocks_disable); ptr++, clkp++) {
840
841 ret = s3c24xx_register_clock(clkp);
842 if (ret < 0) {
843 printk(KERN_ERR "Failed to register clock %s (%d)\n",
844 clkp->name, ret);
845 }
846
847 (clkp->enable)(clkp, 0);
848 }
Ben Dooks9d325f22008-11-21 10:36:05 +0000849
850 s3c_pwmclk_init();
Ben Dookse4d06e32007-02-16 12:12:31 +0100851}