blob: 1307f69abf983e2cd5c2b3ef9a8c07aff354f082 [file] [log] [blame]
Ben Dookse4d06e32007-02-16 12:12:31 +01001/* linux/arch/arm/mach-s3c2443/clock.c
2 *
Ben Dooks4bed36b2010-01-30 10:25:49 +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 Dooks4bed36b2010-01-30 10:25:49 +0200148static struct clk *clk_msysclk_sources[] = {
149 [0] = &clk_mpllref,
150 [1] = &clk_mpll,
151 [2] = &clk_mdivclk,
152 [3] = &clk_mpllref,
153};
Ben Dookse4d06e32007-02-16 12:12:31 +0100154
Ben Dooks4bed36b2010-01-30 10:25:49 +0200155static struct clksrc_clk clk_msysclk = {
156 .clk = {
157 .name = "msysclk",
158 .parent = &clk_xtal,
159 .id = -1,
Ben Dooksb3bf41b2009-12-01 01:24:37 +0000160 },
Ben Dooks4bed36b2010-01-30 10:25:49 +0200161 .sources = &(struct clksrc_sources) {
162 .sources = clk_msysclk_sources,
163 .nr_sources = ARRAY_SIZE(clk_msysclk_sources),
164 },
165 .reg_src = { .reg = S3C2443_CLKSRC, .size = 2, .shift = 3 },
Ben Dookse4d06e32007-02-16 12:12:31 +0100166};
167
Ben Dooksba7622a2008-07-07 18:12:39 +0100168/* armdiv
169 *
170 * this clock is sourced from msysclk and can have a number of
171 * divider values applied to it to then be fed into armclk.
172*/
173
174static struct clk clk_armdiv = {
175 .name = "armdiv",
176 .id = -1,
Ben Dooks4bed36b2010-01-30 10:25:49 +0200177 .parent = &clk_msysclk.clk,
Ben Dooksba7622a2008-07-07 18:12:39 +0100178};
179
180/* armclk
181 *
Ben Dooks4bed36b2010-01-30 10:25:49 +0200182 * this is the clock fed into the ARM core itself, from armdiv or from hclk.
Ben Dooksba7622a2008-07-07 18:12:39 +0100183 */
184
Ben Dooks4bed36b2010-01-30 10:25:49 +0200185static struct clk *clk_arm_sources[] = {
186 [0] = &clk_armdiv,
187 [1] = &clk_h,
188};
Ben Dooksba7622a2008-07-07 18:12:39 +0100189
Ben Dooks4bed36b2010-01-30 10:25:49 +0200190static struct clksrc_clk clk_arm = {
191 .clk = {
192 .name = "armclk",
193 .id = -1,
Ben Dooksb3bf41b2009-12-01 01:24:37 +0000194 },
Ben Dooks4bed36b2010-01-30 10:25:49 +0200195 .sources = &(struct clksrc_sources) {
196 .sources = clk_arm_sources,
197 .nr_sources = ARRAY_SIZE(clk_arm_sources),
198 },
199 .reg_src = { .reg = S3C2443_CLKDIV0, .size = 1, .shift = 13 },
Ben Dooksba7622a2008-07-07 18:12:39 +0100200};
Ben Dookse4d06e32007-02-16 12:12:31 +0100201
202/* esysclk
203 *
204 * this is sourced from either the EPLL or the EPLLref clock
205*/
206
Ben Dooks4bed36b2010-01-30 10:25:49 +0200207static struct clk *clk_sysclk_sources[] = {
208 [0] = &clk_epllref.clk,
209 [1] = &clk_epll,
210};
Ben Dookse4d06e32007-02-16 12:12:31 +0100211
Ben Dooks4bed36b2010-01-30 10:25:49 +0200212static struct clksrc_clk clk_esysclk = {
213 .clk = {
214 .name = "esysclk",
215 .parent = &clk_epll,
216 .id = -1,
Ben Dooksb3bf41b2009-12-01 01:24:37 +0000217 },
Ben Dooks4bed36b2010-01-30 10:25:49 +0200218 .sources = &(struct clksrc_sources) {
219 .sources = clk_sysclk_sources,
220 .nr_sources = ARRAY_SIZE(clk_sysclk_sources),
221 },
222 .reg_src = { .reg = S3C2443_CLKSRC, .size = 1, .shift = 6 },
Ben Dookse4d06e32007-02-16 12:12:31 +0100223};
224
225/* uartclk
226 *
227 * UART baud-rate clock sourced from esysclk via a divisor
228*/
229
Ben Dooks9aa753c2010-01-30 09:19:59 +0200230static struct clksrc_clk clk_uart = {
231 .clk = {
232 .name = "uartclk",
233 .id = -1,
Ben Dooks4bed36b2010-01-30 10:25:49 +0200234 .parent = &clk_esysclk.clk,
Ben Dooksb3bf41b2009-12-01 01:24:37 +0000235 },
Ben Dooks9aa753c2010-01-30 09:19:59 +0200236 .reg_div = { .reg = S3C2443_CLKDIV1, .size = 4, .shift = 8 },
Ben Dookse4d06e32007-02-16 12:12:31 +0100237};
238
Ben Dooks9aa753c2010-01-30 09:19:59 +0200239
Ben Dookse4d06e32007-02-16 12:12:31 +0100240/* hsspi
241 *
242 * high-speed spi clock, sourced from esysclk
243*/
244
Ben Dooks9aa753c2010-01-30 09:19:59 +0200245static struct clksrc_clk clk_hsspi = {
246 .clk = {
247 .name = "hsspi",
248 .id = -1,
Ben Dooks4bed36b2010-01-30 10:25:49 +0200249 .parent = &clk_esysclk.clk,
Ben Dooks9aa753c2010-01-30 09:19:59 +0200250 .ctrlbit = S3C2443_SCLKCON_HSSPICLK,
251 .enable = s3c2443_clkcon_enable_s,
Ben Dooksb3bf41b2009-12-01 01:24:37 +0000252 },
Ben Dooks9aa753c2010-01-30 09:19:59 +0200253 .reg_div = { .reg = S3C2443_CLKDIV1, .size = 2, .shift = 4 },
Ben Dookse4d06e32007-02-16 12:12:31 +0100254};
255
256/* usbhost
257 *
258 * usb host bus-clock, usually 48MHz to provide USB bus clock timing
259*/
260
Ben Dooks9aa753c2010-01-30 09:19:59 +0200261static struct clksrc_clk clk_usb_bus_host = {
262 .clk = {
263 .name = "usb-bus-host-parent",
264 .id = -1,
Ben Dooks4bed36b2010-01-30 10:25:49 +0200265 .parent = &clk_esysclk.clk,
Ben Dooks9aa753c2010-01-30 09:19:59 +0200266 .ctrlbit = S3C2443_SCLKCON_USBHOST,
267 .enable = s3c2443_clkcon_enable_s,
Ben Dooksb3bf41b2009-12-01 01:24:37 +0000268 },
Ben Dooks9aa753c2010-01-30 09:19:59 +0200269 .reg_div = { .reg = S3C2443_CLKDIV1, .size = 2, .shift = 4 },
Ben Dookse4d06e32007-02-16 12:12:31 +0100270};
271
272/* clk_hsmcc_div
273 *
274 * this clock is sourced from epll, and is fed through a divider,
275 * to a mux controlled by sclkcon where either it or a extclk can
276 * be fed to the hsmmc block
277*/
278
Ben Dooks9aa753c2010-01-30 09:19:59 +0200279static struct clksrc_clk clk_hsmmc_div = {
280 .clk = {
281 .name = "hsmmc-div",
282 .id = -1,
Ben Dooks4bed36b2010-01-30 10:25:49 +0200283 .parent = &clk_esysclk.clk,
Ben Dooksb3bf41b2009-12-01 01:24:37 +0000284 },
Ben Dooks9aa753c2010-01-30 09:19:59 +0200285 .reg_div = { .reg = S3C2443_CLKDIV1, .size = 2, .shift = 6 },
Ben Dookse4d06e32007-02-16 12:12:31 +0100286};
287
288static int s3c2443_setparent_hsmmc(struct clk *clk, struct clk *parent)
289{
290 unsigned long clksrc = __raw_readl(S3C2443_SCLKCON);
291
292 clksrc &= ~(S3C2443_SCLKCON_HSMMCCLK_EXT |
293 S3C2443_SCLKCON_HSMMCCLK_EPLL);
294
295 if (parent == &clk_epll)
296 clksrc |= S3C2443_SCLKCON_HSMMCCLK_EPLL;
297 else if (parent == &clk_ext)
298 clksrc |= S3C2443_SCLKCON_HSMMCCLK_EXT;
299 else
300 return -EINVAL;
301
302 if (clk->usage > 0) {
303 __raw_writel(clksrc, S3C2443_SCLKCON);
304 }
305
306 clk->parent = parent;
307 return 0;
308}
309
310static int s3c2443_enable_hsmmc(struct clk *clk, int enable)
311{
312 return s3c2443_setparent_hsmmc(clk, clk->parent);
313}
314
315static struct clk clk_hsmmc = {
316 .name = "hsmmc-if",
317 .id = -1,
Ben Dooks9aa753c2010-01-30 09:19:59 +0200318 .parent = &clk_hsmmc_div.clk,
Ben Dookse4d06e32007-02-16 12:12:31 +0100319 .enable = s3c2443_enable_hsmmc,
Ben Dooksb3bf41b2009-12-01 01:24:37 +0000320 .ops = &(struct clk_ops) {
321 .set_parent = s3c2443_setparent_hsmmc,
322 },
Ben Dookse4d06e32007-02-16 12:12:31 +0100323};
324
325/* i2s_eplldiv
326 *
Ben Dooks9aa753c2010-01-30 09:19:59 +0200327 * This clock is the output from the I2S divisor of ESYSCLK, and is seperate
328 * from the mux that comes after it (cannot merge into one single clock)
Ben Dookse4d06e32007-02-16 12:12:31 +0100329*/
330
Ben Dooks9aa753c2010-01-30 09:19:59 +0200331static struct clksrc_clk clk_i2s_eplldiv = {
332 .clk = {
333 .name = "i2s-eplldiv",
334 .id = -1,
Ben Dooks4bed36b2010-01-30 10:25:49 +0200335 .parent = &clk_esysclk.clk,
Ben Dooksb3bf41b2009-12-01 01:24:37 +0000336 },
Ben Dooks9aa753c2010-01-30 09:19:59 +0200337 .reg_div = { .reg = S3C2443_CLKDIV1, .size = 4, .shift = 12, },
Ben Dookse4d06e32007-02-16 12:12:31 +0100338};
339
340/* i2s-ref
341 *
342 * i2s bus reference clock, selectable from external, esysclk or epllref
Ben Dooks9aa753c2010-01-30 09:19:59 +0200343 *
344 * Note, this used to be two clocks, but was compressed into one.
Ben Dookse4d06e32007-02-16 12:12:31 +0100345*/
346
Ben Dooks9aa753c2010-01-30 09:19:59 +0200347struct clk *clk_i2s_srclist[] = {
348 [0] = &clk_i2s_eplldiv.clk,
349 [1] = &clk_i2s_ext,
350 [2] = &clk_epllref.clk,
351 [3] = &clk_epllref.clk,
352};
Ben Dookse4d06e32007-02-16 12:12:31 +0100353
Ben Dooks9aa753c2010-01-30 09:19:59 +0200354static struct clksrc_clk clk_i2s = {
355 .clk = {
356 .name = "i2s-if",
357 .id = -1,
358 .ctrlbit = S3C2443_SCLKCON_I2SCLK,
359 .enable = s3c2443_clkcon_enable_s,
Ben Dookse4d06e32007-02-16 12:12:31 +0100360
Ben Dooksb3bf41b2009-12-01 01:24:37 +0000361 },
Ben Dooks9aa753c2010-01-30 09:19:59 +0200362 .sources = &(struct clksrc_sources) {
363 .sources = clk_i2s_srclist,
364 .nr_sources = ARRAY_SIZE(clk_i2s_srclist),
365 },
366 .reg_src = { .reg = S3C2443_CLKSRC, .size = 2, .shift = 14 },
Ben Dookse4d06e32007-02-16 12:12:31 +0100367};
368
369/* cam-if
370 *
371 * camera interface bus-clock, divided down from esysclk
372*/
373
Ben Dooks9aa753c2010-01-30 09:19:59 +0200374static struct clksrc_clk clk_cam = {
375 .clk = {
376 .name = "camif-upll", /* same as 2440 name */
377 .id = -1,
Ben Dooks4bed36b2010-01-30 10:25:49 +0200378 .parent = &clk_esysclk.clk,
Ben Dooks9aa753c2010-01-30 09:19:59 +0200379 .ctrlbit = S3C2443_SCLKCON_CAMCLK,
380 .enable = s3c2443_clkcon_enable_s,
Ben Dooksb3bf41b2009-12-01 01:24:37 +0000381 },
Ben Dooks9aa753c2010-01-30 09:19:59 +0200382 .reg_div = { .reg = S3C2443_CLKDIV1, .size = 4, .shift = 26 },
Ben Dookse4d06e32007-02-16 12:12:31 +0100383};
384
385/* display-if
386 *
387 * display interface clock, divided from esysclk
388*/
389
Ben Dooks9aa753c2010-01-30 09:19:59 +0200390static struct clksrc_clk clk_display = {
391 .clk = {
392 .name = "display-if",
393 .id = -1,
Ben Dooks4bed36b2010-01-30 10:25:49 +0200394 .parent = &clk_esysclk.clk,
Ben Dooks9aa753c2010-01-30 09:19:59 +0200395 .ctrlbit = S3C2443_SCLKCON_DISPCLK,
396 .enable = s3c2443_clkcon_enable_s,
Ben Dooksb3bf41b2009-12-01 01:24:37 +0000397 },
Ben Dooks9aa753c2010-01-30 09:19:59 +0200398 .reg_div = { .reg = S3C2443_CLKDIV1, .size = 8, .shift = 16 },
Ben Dookse4d06e32007-02-16 12:12:31 +0100399};
400
Ben Dooks2e16c272008-07-07 18:12:40 +0100401/* prediv
402 *
403 * this divides the msysclk down to pass to h/p/etc.
404 */
405
406static unsigned long s3c2443_prediv_getrate(struct clk *clk)
407{
408 unsigned long rate = clk_get_rate(clk->parent);
409 unsigned long clkdiv0 = __raw_readl(S3C2443_CLKDIV0);
410
411 clkdiv0 &= S3C2443_CLKDIV0_PREDIV_MASK;
412 clkdiv0 >>= S3C2443_CLKDIV0_PREDIV_SHIFT;
413
414 return rate / (clkdiv0 + 1);
415}
416
417static struct clk clk_prediv = {
418 .name = "prediv",
419 .id = -1,
Ben Dooks4bed36b2010-01-30 10:25:49 +0200420 .parent = &clk_msysclk.clk,
Ben Dooksb3bf41b2009-12-01 01:24:37 +0000421 .ops = &(struct clk_ops) {
422 .get_rate = s3c2443_prediv_getrate,
423 },
Ben Dooks2e16c272008-07-07 18:12:40 +0100424};
425
Ben Dookse4d06e32007-02-16 12:12:31 +0100426/* standard clock definitions */
427
428static struct clk init_clocks_disable[] = {
429 {
430 .name = "nand",
431 .id = -1,
432 .parent = &clk_h,
433 }, {
434 .name = "sdi",
435 .id = -1,
436 .parent = &clk_p,
437 .enable = s3c2443_clkcon_enable_p,
438 .ctrlbit = S3C2443_PCLKCON_SDI,
439 }, {
440 .name = "adc",
441 .id = -1,
442 .parent = &clk_p,
443 .enable = s3c2443_clkcon_enable_p,
444 .ctrlbit = S3C2443_PCLKCON_ADC,
445 }, {
446 .name = "i2c",
447 .id = -1,
448 .parent = &clk_p,
449 .enable = s3c2443_clkcon_enable_p,
450 .ctrlbit = S3C2443_PCLKCON_IIC,
451 }, {
452 .name = "iis",
453 .id = -1,
454 .parent = &clk_p,
455 .enable = s3c2443_clkcon_enable_p,
456 .ctrlbit = S3C2443_PCLKCON_IIS,
457 }, {
458 .name = "spi",
459 .id = 0,
460 .parent = &clk_p,
461 .enable = s3c2443_clkcon_enable_p,
462 .ctrlbit = S3C2443_PCLKCON_SPI0,
463 }, {
464 .name = "spi",
465 .id = 1,
466 .parent = &clk_p,
467 .enable = s3c2443_clkcon_enable_p,
468 .ctrlbit = S3C2443_PCLKCON_SPI1,
469 }
470};
471
472static struct clk init_clocks[] = {
473 {
474 .name = "dma",
475 .id = 0,
476 .parent = &clk_h,
477 .enable = s3c2443_clkcon_enable_h,
478 .ctrlbit = S3C2443_HCLKCON_DMA0,
479 }, {
480 .name = "dma",
481 .id = 1,
482 .parent = &clk_h,
483 .enable = s3c2443_clkcon_enable_h,
484 .ctrlbit = S3C2443_HCLKCON_DMA1,
485 }, {
486 .name = "dma",
487 .id = 2,
488 .parent = &clk_h,
489 .enable = s3c2443_clkcon_enable_h,
490 .ctrlbit = S3C2443_HCLKCON_DMA2,
491 }, {
492 .name = "dma",
493 .id = 3,
494 .parent = &clk_h,
495 .enable = s3c2443_clkcon_enable_h,
496 .ctrlbit = S3C2443_HCLKCON_DMA3,
497 }, {
498 .name = "dma",
499 .id = 4,
500 .parent = &clk_h,
501 .enable = s3c2443_clkcon_enable_h,
502 .ctrlbit = S3C2443_HCLKCON_DMA4,
503 }, {
504 .name = "dma",
505 .id = 5,
506 .parent = &clk_h,
507 .enable = s3c2443_clkcon_enable_h,
508 .ctrlbit = S3C2443_HCLKCON_DMA5,
509 }, {
510 .name = "lcd",
511 .id = -1,
512 .parent = &clk_h,
513 .enable = s3c2443_clkcon_enable_h,
514 .ctrlbit = S3C2443_HCLKCON_LCDC,
515 }, {
516 .name = "gpio",
517 .id = -1,
518 .parent = &clk_p,
519 .enable = s3c2443_clkcon_enable_p,
520 .ctrlbit = S3C2443_PCLKCON_GPIO,
521 }, {
522 .name = "usb-host",
523 .id = -1,
524 .parent = &clk_h,
525 .enable = s3c2443_clkcon_enable_h,
526 .ctrlbit = S3C2443_HCLKCON_USBH,
527 }, {
528 .name = "usb-device",
529 .id = -1,
530 .parent = &clk_h,
531 .enable = s3c2443_clkcon_enable_h,
532 .ctrlbit = S3C2443_HCLKCON_USBD,
533 }, {
Ben Dooks67364332007-05-20 17:17:32 +0100534 .name = "hsmmc",
535 .id = -1,
536 .parent = &clk_h,
537 .enable = s3c2443_clkcon_enable_h,
538 .ctrlbit = S3C2443_HCLKCON_HSMMC,
539 }, {
540 .name = "cfc",
541 .id = -1,
542 .parent = &clk_h,
543 .enable = s3c2443_clkcon_enable_h,
544 .ctrlbit = S3C2443_HCLKCON_CFC,
Ben Dooks67364332007-05-20 17:17:32 +0100545 }, {
546 .name = "ssmc",
547 .id = -1,
548 .parent = &clk_h,
549 .enable = s3c2443_clkcon_enable_h,
550 .ctrlbit = S3C2443_HCLKCON_SSMC,
551 }, {
Ben Dookse4d06e32007-02-16 12:12:31 +0100552 .name = "timers",
553 .id = -1,
554 .parent = &clk_p,
555 .enable = s3c2443_clkcon_enable_p,
556 .ctrlbit = S3C2443_PCLKCON_PWMT,
557 }, {
558 .name = "uart",
559 .id = 0,
560 .parent = &clk_p,
561 .enable = s3c2443_clkcon_enable_p,
562 .ctrlbit = S3C2443_PCLKCON_UART0,
563 }, {
564 .name = "uart",
565 .id = 1,
566 .parent = &clk_p,
567 .enable = s3c2443_clkcon_enable_p,
568 .ctrlbit = S3C2443_PCLKCON_UART1,
569 }, {
570 .name = "uart",
571 .id = 2,
572 .parent = &clk_p,
573 .enable = s3c2443_clkcon_enable_p,
574 .ctrlbit = S3C2443_PCLKCON_UART2,
575 }, {
576 .name = "uart",
577 .id = 3,
578 .parent = &clk_p,
579 .enable = s3c2443_clkcon_enable_p,
580 .ctrlbit = S3C2443_PCLKCON_UART3,
581 }, {
582 .name = "rtc",
583 .id = -1,
584 .parent = &clk_p,
585 .enable = s3c2443_clkcon_enable_p,
586 .ctrlbit = S3C2443_PCLKCON_RTC,
587 }, {
588 .name = "watchdog",
589 .id = -1,
590 .parent = &clk_p,
591 .ctrlbit = S3C2443_PCLKCON_WDT,
592 }, {
593 .name = "usb-bus-host",
594 .id = -1,
Ben Dooks9aa753c2010-01-30 09:19:59 +0200595 .parent = &clk_usb_bus_host.clk,
Ben Dooks67364332007-05-20 17:17:32 +0100596 }, {
597 .name = "ac97",
Graeme Gregoryb8b69702007-05-09 15:55:24 +0100598 .id = -1,
599 .parent = &clk_p,
600 .ctrlbit = S3C2443_PCLKCON_AC97,
Ben Dookse4d06e32007-02-16 12:12:31 +0100601 }
602};
603
604/* clocks to add where we need to check their parentage */
605
Ben Dooks9aa753c2010-01-30 09:19:59 +0200606static struct clksrc_clk __initdata *init_list[] = {
607 &clk_epllref, /* should be first */
Ben Dooks4bed36b2010-01-30 10:25:49 +0200608 &clk_esysclk,
609 &clk_msysclk,
610 &clk_arm,
Ben Dooks9aa753c2010-01-30 09:19:59 +0200611 &clk_i2s_eplldiv,
612 &clk_i2s,
613 &clk_cam,
614 &clk_uart,
615 &clk_display,
616 &clk_hsmmc_div,
617 &clk_usb_bus_host,
618};
619
Ben Dookse4d06e32007-02-16 12:12:31 +0100620static void __init s3c2443_clk_initparents(void)
621{
Ben Dooks9aa753c2010-01-30 09:19:59 +0200622 int ptr;
Ben Dookse4d06e32007-02-16 12:12:31 +0100623
Ben Dooks9aa753c2010-01-30 09:19:59 +0200624 for (ptr = 0; ptr < ARRAY_SIZE(init_list); ptr++)
Ben Dooks4bed36b2010-01-30 10:25:49 +0200625 s3c_set_clksrc(init_list[ptr], true);
Ben Dookse4d06e32007-02-16 12:12:31 +0100626}
627
628/* armdiv divisor table */
629
630static unsigned int armdiv[16] = {
631 [S3C2443_CLKDIV0_ARMDIV_1 >> S3C2443_CLKDIV0_ARMDIV_SHIFT] = 1,
632 [S3C2443_CLKDIV0_ARMDIV_2 >> S3C2443_CLKDIV0_ARMDIV_SHIFT] = 2,
633 [S3C2443_CLKDIV0_ARMDIV_3 >> S3C2443_CLKDIV0_ARMDIV_SHIFT] = 3,
634 [S3C2443_CLKDIV0_ARMDIV_4 >> S3C2443_CLKDIV0_ARMDIV_SHIFT] = 4,
635 [S3C2443_CLKDIV0_ARMDIV_6 >> S3C2443_CLKDIV0_ARMDIV_SHIFT] = 6,
636 [S3C2443_CLKDIV0_ARMDIV_8 >> S3C2443_CLKDIV0_ARMDIV_SHIFT] = 8,
637 [S3C2443_CLKDIV0_ARMDIV_12 >> S3C2443_CLKDIV0_ARMDIV_SHIFT] = 12,
638 [S3C2443_CLKDIV0_ARMDIV_16 >> S3C2443_CLKDIV0_ARMDIV_SHIFT] = 16,
639};
640
641static inline unsigned int s3c2443_fclk_div(unsigned long clkcon0)
642{
643 clkcon0 &= S3C2443_CLKDIV0_ARMDIV_MASK;
644
645 return armdiv[clkcon0 >> S3C2443_CLKDIV0_ARMDIV_SHIFT];
646}
647
Ben Dooks2e16c272008-07-07 18:12:40 +0100648static inline unsigned long s3c2443_get_hdiv(unsigned long clkcon0)
Ben Dookse4d06e32007-02-16 12:12:31 +0100649{
Ben Dooks2e16c272008-07-07 18:12:40 +0100650 clkcon0 &= S3C2443_CLKDIV0_HCLKDIV_MASK;
Ben Dookse4d06e32007-02-16 12:12:31 +0100651
652 return clkcon0 + 1;
653}
654
655/* clocks to add straight away */
656
Ben Dooks9aa753c2010-01-30 09:19:59 +0200657static struct clksrc_clk *clksrcs[] __initdata = {
Ben Dookse4d06e32007-02-16 12:12:31 +0100658 &clk_usb_bus_host,
Ben Dookse4d06e32007-02-16 12:12:31 +0100659 &clk_epllref,
Ben Dooks4bed36b2010-01-30 10:25:49 +0200660 &clk_esysclk,
661 &clk_msysclk,
662 &clk_arm,
Ben Dookse4d06e32007-02-16 12:12:31 +0100663 &clk_uart,
664 &clk_display,
665 &clk_cam,
666 &clk_i2s_eplldiv,
667 &clk_i2s,
668 &clk_hsspi,
669 &clk_hsmmc_div,
Ben Dooks9aa753c2010-01-30 09:19:59 +0200670};
671
672static struct clk *clks[] __initdata = {
673 &clk_ext,
674 &clk_epll,
675 &clk_usb_bus,
Ben Dooks9aa753c2010-01-30 09:19:59 +0200676 &clk_mpllref,
Ben Dookse4d06e32007-02-16 12:12:31 +0100677 &clk_hsmmc,
Ben Dooksba7622a2008-07-07 18:12:39 +0100678 &clk_armdiv,
Ben Dooks2e16c272008-07-07 18:12:40 +0100679 &clk_prediv,
Ben Dookse4d06e32007-02-16 12:12:31 +0100680};
681
Ben Dookse4253822008-10-21 14:06:38 +0100682void __init_or_cpufreq s3c2443_setup_clocks(void)
Ben Dookse4d06e32007-02-16 12:12:31 +0100683{
Ben Dookse4d06e32007-02-16 12:12:31 +0100684 unsigned long mpllcon = __raw_readl(S3C2443_MPLLCON);
685 unsigned long clkdiv0 = __raw_readl(S3C2443_CLKDIV0);
Ben Dookse4253822008-10-21 14:06:38 +0100686 struct clk *xtal_clk;
687 unsigned long xtal;
Ben Dookse4d06e32007-02-16 12:12:31 +0100688 unsigned long pll;
689 unsigned long fclk;
690 unsigned long hclk;
691 unsigned long pclk;
Ben Dookse4d06e32007-02-16 12:12:31 +0100692
Ben Dookse4253822008-10-21 14:06:38 +0100693 xtal_clk = clk_get(NULL, "xtal");
694 xtal = clk_get_rate(xtal_clk);
695 clk_put(xtal_clk);
Ben Dooks2e16c272008-07-07 18:12:40 +0100696
Ben Dookse4d06e32007-02-16 12:12:31 +0100697 pll = s3c2443_get_mpll(mpllcon, xtal);
Ben Dooks4bed36b2010-01-30 10:25:49 +0200698 clk_msysclk.clk.rate = pll;
Ben Dookse4d06e32007-02-16 12:12:31 +0100699
700 fclk = pll / s3c2443_fclk_div(clkdiv0);
Ben Dooks2e16c272008-07-07 18:12:40 +0100701 hclk = s3c2443_prediv_getrate(&clk_prediv);
Ben Dooks5c378662008-10-16 16:46:09 +0100702 hclk /= s3c2443_get_hdiv(clkdiv0);
Ben Dookse4d06e32007-02-16 12:12:31 +0100703 pclk = hclk / ((clkdiv0 & S3C2443_CLKDIV0_HALF_PCLK) ? 2 : 1);
704
Ben Dookse4253822008-10-21 14:06:38 +0100705 s3c24xx_setup_clocks(fclk, hclk, pclk);
Ben Dookse4d06e32007-02-16 12:12:31 +0100706
707 printk("S3C2443: mpll %s %ld.%03ld MHz, cpu %ld.%03ld MHz, mem %ld.%03ld MHz, pclk %ld.%03ld MHz\n",
708 (mpllcon & S3C2443_PLLCON_OFF) ? "off":"on",
709 print_mhz(pll), print_mhz(fclk),
710 print_mhz(hclk), print_mhz(pclk));
711
Ben Dookse4253822008-10-21 14:06:38 +0100712 s3c24xx_setup_clocks(fclk, hclk, pclk);
713}
714
715void __init s3c2443_init_clocks(int xtal)
716{
717 struct clk *clkp;
718 unsigned long epllcon = __raw_readl(S3C2443_EPLLCON);
719 int ret;
720 int ptr;
721
722 /* s3c2443 parents h and p clocks from prediv */
723 clk_h.parent = &clk_prediv;
724 clk_p.parent = &clk_prediv;
725
726 s3c24xx_register_baseclocks(xtal);
727 s3c2443_setup_clocks();
Ben Dookse4d06e32007-02-16 12:12:31 +0100728 s3c2443_clk_initparents();
729
730 for (ptr = 0; ptr < ARRAY_SIZE(clks); ptr++) {
731 clkp = clks[ptr];
732
733 ret = s3c24xx_register_clock(clkp);
734 if (ret < 0) {
735 printk(KERN_ERR "Failed to register clock %s (%d)\n",
736 clkp->name, ret);
737 }
738 }
739
Ben Dooks9aa753c2010-01-30 09:19:59 +0200740 for (ptr = 0; ptr < ARRAY_SIZE(clksrcs); ptr++)
741 s3c_register_clksrc(clksrcs[ptr], 1);
742
Ben Dookse4d06e32007-02-16 12:12:31 +0100743 clk_epll.rate = s3c2443_get_epll(epllcon, xtal);
Ben Dooks9aa753c2010-01-30 09:19:59 +0200744 clk_epll.parent = &clk_epllref.clk;
745 clk_usb_bus.parent = &clk_usb_bus_host.clk;
Ben Dookse4d06e32007-02-16 12:12:31 +0100746
747 /* ensure usb bus clock is within correct rate of 48MHz */
748
Ben Dooks9aa753c2010-01-30 09:19:59 +0200749 if (clk_get_rate(&clk_usb_bus_host.clk) != (48 * 1000 * 1000)) {
Ben Dookse4d06e32007-02-16 12:12:31 +0100750 printk(KERN_INFO "Warning: USB host bus not at 48MHz\n");
Ben Dooks9aa753c2010-01-30 09:19:59 +0200751 clk_set_rate(&clk_usb_bus_host.clk, 48*1000*1000);
Ben Dookse4d06e32007-02-16 12:12:31 +0100752 }
753
754 printk("S3C2443: epll %s %ld.%03ld MHz, usb-bus %ld.%03ld MHz\n",
755 (epllcon & S3C2443_PLLCON_OFF) ? "off":"on",
756 print_mhz(clk_get_rate(&clk_epll)),
757 print_mhz(clk_get_rate(&clk_usb_bus)));
758
759 /* register clocks from clock array */
760
Ben Dooks1d9f13c2010-01-06 01:21:38 +0900761 s3c_register_clocks(init_clocks, ARRAY_SIZE(init_clocks));
Ben Dookse4d06e32007-02-16 12:12:31 +0100762
763 /* We must be careful disabling the clocks we are not intending to
Robert P. J. Day3a4fa0a2007-10-19 23:10:43 +0200764 * be using at boot time, as subsystems such as the LCD which do
Ben Dookse4d06e32007-02-16 12:12:31 +0100765 * their own DMA requests to the bus can cause the system to lockup
766 * if they where in the middle of requesting bus access.
767 *
768 * Disabling the LCD clock if the LCD is active is very dangerous,
769 * and therefore the bootloader should be careful to not enable
770 * the LCD clock if it is not needed.
771 */
772
773 /* install (and disable) the clocks we do not need immediately */
774
775 clkp = init_clocks_disable;
776 for (ptr = 0; ptr < ARRAY_SIZE(init_clocks_disable); ptr++, clkp++) {
777
778 ret = s3c24xx_register_clock(clkp);
779 if (ret < 0) {
780 printk(KERN_ERR "Failed to register clock %s (%d)\n",
781 clkp->name, ret);
782 }
783
784 (clkp->enable)(clkp, 0);
785 }
Ben Dooks9d325f22008-11-21 10:36:05 +0000786
787 s3c_pwmclk_init();
Ben Dookse4d06e32007-02-16 12:12:31 +0100788}