blob: 3fa37aa62aabbcba70a5f51acb0c848fa93c48b8 [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 Dookse4d06e32007-02-16 12:12:31 +010086/* clock selections */
87
Ben Dooks2dd5f182010-01-30 10:46:52 +020088/* mpllref is a direct descendant of clk_xtal by default, but it is not
89 * elided as the EPLL can be either sourced by the XTAL or EXTCLK and as
90 * such directly equating the two source clocks is impossible.
91 */
Ben Dookse4d06e32007-02-16 12:12:31 +010092static struct clk clk_mpllref = {
93 .name = "mpllref",
94 .parent = &clk_xtal,
95 .id = -1,
96};
97
98#if 0
99static struct clk clk_mpll = {
100 .name = "mpll",
101 .parent = &clk_mpllref,
102 .id = -1,
103};
104#endif
105
Ben Dookse4d06e32007-02-16 12:12:31 +0100106static struct clk clk_i2s_ext = {
107 .name = "i2s-ext",
108 .id = -1,
109};
110
Ben Dooks9aa753c2010-01-30 09:19:59 +0200111static struct clk *clk_epllref_sources[] = {
112 [0] = &clk_mpllref,
113 [1] = &clk_mpllref,
114 [2] = &clk_xtal,
115 [3] = &clk_ext,
116};
Ben Dookse4d06e32007-02-16 12:12:31 +0100117
Ben Dooks9aa753c2010-01-30 09:19:59 +0200118static struct clksrc_clk clk_epllref = {
119 .clk = {
120 .name = "epllref",
121 .id = -1,
Ben Dooksb3bf41b2009-12-01 01:24:37 +0000122 },
Ben Dooks9aa753c2010-01-30 09:19:59 +0200123 .sources = &(struct clksrc_sources) {
124 .sources = clk_epllref_sources,
125 .nr_sources = ARRAY_SIZE(clk_epllref_sources),
126 },
127 .reg_src = { .reg = S3C2443_CLKSRC, .size = 2, .shift = 7 },
Ben Dookse4d06e32007-02-16 12:12:31 +0100128};
129
130static unsigned long s3c2443_getrate_mdivclk(struct clk *clk)
131{
132 unsigned long parent_rate = clk_get_rate(clk->parent);
133 unsigned long div = __raw_readl(S3C2443_CLKDIV0);
134
135 div &= S3C2443_CLKDIV0_EXTDIV_MASK;
136 div >>= (S3C2443_CLKDIV0_EXTDIV_SHIFT-1); /* x2 */
137
138 return parent_rate / (div + 1);
139}
140
141static struct clk clk_mdivclk = {
142 .name = "mdivclk",
143 .parent = &clk_mpllref,
144 .id = -1,
Ben Dooksb3bf41b2009-12-01 01:24:37 +0000145 .ops = &(struct clk_ops) {
146 .get_rate = s3c2443_getrate_mdivclk,
147 },
Ben Dookse4d06e32007-02-16 12:12:31 +0100148};
149
Ben Dooks4bed36b2010-01-30 10:25:49 +0200150static struct clk *clk_msysclk_sources[] = {
151 [0] = &clk_mpllref,
152 [1] = &clk_mpll,
153 [2] = &clk_mdivclk,
154 [3] = &clk_mpllref,
155};
Ben Dookse4d06e32007-02-16 12:12:31 +0100156
Ben Dooks4bed36b2010-01-30 10:25:49 +0200157static struct clksrc_clk clk_msysclk = {
158 .clk = {
159 .name = "msysclk",
160 .parent = &clk_xtal,
161 .id = -1,
Ben Dooksb3bf41b2009-12-01 01:24:37 +0000162 },
Ben Dooks4bed36b2010-01-30 10:25:49 +0200163 .sources = &(struct clksrc_sources) {
164 .sources = clk_msysclk_sources,
165 .nr_sources = ARRAY_SIZE(clk_msysclk_sources),
166 },
167 .reg_src = { .reg = S3C2443_CLKSRC, .size = 2, .shift = 3 },
Ben Dookse4d06e32007-02-16 12:12:31 +0100168};
169
Ben Dooksba7622a2008-07-07 18:12:39 +0100170/* armdiv
171 *
172 * this clock is sourced from msysclk and can have a number of
173 * divider values applied to it to then be fed into armclk.
174*/
175
176static struct clk clk_armdiv = {
177 .name = "armdiv",
178 .id = -1,
Ben Dooks4bed36b2010-01-30 10:25:49 +0200179 .parent = &clk_msysclk.clk,
Ben Dooksba7622a2008-07-07 18:12:39 +0100180};
181
182/* armclk
183 *
Ben Dooks4bed36b2010-01-30 10:25:49 +0200184 * this is the clock fed into the ARM core itself, from armdiv or from hclk.
Ben Dooksba7622a2008-07-07 18:12:39 +0100185 */
186
Ben Dooks4bed36b2010-01-30 10:25:49 +0200187static struct clk *clk_arm_sources[] = {
188 [0] = &clk_armdiv,
189 [1] = &clk_h,
190};
Ben Dooksba7622a2008-07-07 18:12:39 +0100191
Ben Dooks4bed36b2010-01-30 10:25:49 +0200192static struct clksrc_clk clk_arm = {
193 .clk = {
194 .name = "armclk",
195 .id = -1,
Ben Dooksb3bf41b2009-12-01 01:24:37 +0000196 },
Ben Dooks4bed36b2010-01-30 10:25:49 +0200197 .sources = &(struct clksrc_sources) {
198 .sources = clk_arm_sources,
199 .nr_sources = ARRAY_SIZE(clk_arm_sources),
200 },
201 .reg_src = { .reg = S3C2443_CLKDIV0, .size = 1, .shift = 13 },
Ben Dooksba7622a2008-07-07 18:12:39 +0100202};
Ben Dookse4d06e32007-02-16 12:12:31 +0100203
204/* esysclk
205 *
206 * this is sourced from either the EPLL or the EPLLref clock
207*/
208
Ben Dooks4bed36b2010-01-30 10:25:49 +0200209static struct clk *clk_sysclk_sources[] = {
210 [0] = &clk_epllref.clk,
211 [1] = &clk_epll,
212};
Ben Dookse4d06e32007-02-16 12:12:31 +0100213
Ben Dooks4bed36b2010-01-30 10:25:49 +0200214static struct clksrc_clk clk_esysclk = {
215 .clk = {
216 .name = "esysclk",
217 .parent = &clk_epll,
218 .id = -1,
Ben Dooksb3bf41b2009-12-01 01:24:37 +0000219 },
Ben Dooks4bed36b2010-01-30 10:25:49 +0200220 .sources = &(struct clksrc_sources) {
221 .sources = clk_sysclk_sources,
222 .nr_sources = ARRAY_SIZE(clk_sysclk_sources),
223 },
224 .reg_src = { .reg = S3C2443_CLKSRC, .size = 1, .shift = 6 },
Ben Dookse4d06e32007-02-16 12:12:31 +0100225};
226
227/* uartclk
228 *
229 * UART baud-rate clock sourced from esysclk via a divisor
230*/
231
Ben Dooks9aa753c2010-01-30 09:19:59 +0200232static struct clksrc_clk clk_uart = {
233 .clk = {
234 .name = "uartclk",
235 .id = -1,
Ben Dooks4bed36b2010-01-30 10:25:49 +0200236 .parent = &clk_esysclk.clk,
Ben Dooksb3bf41b2009-12-01 01:24:37 +0000237 },
Ben Dooks9aa753c2010-01-30 09:19:59 +0200238 .reg_div = { .reg = S3C2443_CLKDIV1, .size = 4, .shift = 8 },
Ben Dookse4d06e32007-02-16 12:12:31 +0100239};
240
Ben Dooks9aa753c2010-01-30 09:19:59 +0200241
Ben Dookse4d06e32007-02-16 12:12:31 +0100242/* hsspi
243 *
244 * high-speed spi clock, sourced from esysclk
245*/
246
Ben Dooks9aa753c2010-01-30 09:19:59 +0200247static struct clksrc_clk clk_hsspi = {
248 .clk = {
249 .name = "hsspi",
250 .id = -1,
Ben Dooks4bed36b2010-01-30 10:25:49 +0200251 .parent = &clk_esysclk.clk,
Ben Dooks9aa753c2010-01-30 09:19:59 +0200252 .ctrlbit = S3C2443_SCLKCON_HSSPICLK,
253 .enable = s3c2443_clkcon_enable_s,
Ben Dooksb3bf41b2009-12-01 01:24:37 +0000254 },
Ben Dooks9aa753c2010-01-30 09:19:59 +0200255 .reg_div = { .reg = S3C2443_CLKDIV1, .size = 2, .shift = 4 },
Ben Dookse4d06e32007-02-16 12:12:31 +0100256};
257
258/* usbhost
259 *
260 * usb host bus-clock, usually 48MHz to provide USB bus clock timing
261*/
262
Ben Dooks9aa753c2010-01-30 09:19:59 +0200263static struct clksrc_clk clk_usb_bus_host = {
264 .clk = {
265 .name = "usb-bus-host-parent",
266 .id = -1,
Ben Dooks4bed36b2010-01-30 10:25:49 +0200267 .parent = &clk_esysclk.clk,
Ben Dooks9aa753c2010-01-30 09:19:59 +0200268 .ctrlbit = S3C2443_SCLKCON_USBHOST,
269 .enable = s3c2443_clkcon_enable_s,
Ben Dooksb3bf41b2009-12-01 01:24:37 +0000270 },
Ben Dooks9aa753c2010-01-30 09:19:59 +0200271 .reg_div = { .reg = S3C2443_CLKDIV1, .size = 2, .shift = 4 },
Ben Dookse4d06e32007-02-16 12:12:31 +0100272};
273
274/* clk_hsmcc_div
275 *
276 * this clock is sourced from epll, and is fed through a divider,
277 * to a mux controlled by sclkcon where either it or a extclk can
278 * be fed to the hsmmc block
279*/
280
Ben Dooks9aa753c2010-01-30 09:19:59 +0200281static struct clksrc_clk clk_hsmmc_div = {
282 .clk = {
283 .name = "hsmmc-div",
284 .id = -1,
Ben Dooks4bed36b2010-01-30 10:25:49 +0200285 .parent = &clk_esysclk.clk,
Ben Dooksb3bf41b2009-12-01 01:24:37 +0000286 },
Ben Dooks9aa753c2010-01-30 09:19:59 +0200287 .reg_div = { .reg = S3C2443_CLKDIV1, .size = 2, .shift = 6 },
Ben Dookse4d06e32007-02-16 12:12:31 +0100288};
289
290static int s3c2443_setparent_hsmmc(struct clk *clk, struct clk *parent)
291{
292 unsigned long clksrc = __raw_readl(S3C2443_SCLKCON);
293
294 clksrc &= ~(S3C2443_SCLKCON_HSMMCCLK_EXT |
295 S3C2443_SCLKCON_HSMMCCLK_EPLL);
296
297 if (parent == &clk_epll)
298 clksrc |= S3C2443_SCLKCON_HSMMCCLK_EPLL;
299 else if (parent == &clk_ext)
300 clksrc |= S3C2443_SCLKCON_HSMMCCLK_EXT;
301 else
302 return -EINVAL;
303
304 if (clk->usage > 0) {
305 __raw_writel(clksrc, S3C2443_SCLKCON);
306 }
307
308 clk->parent = parent;
309 return 0;
310}
311
312static int s3c2443_enable_hsmmc(struct clk *clk, int enable)
313{
314 return s3c2443_setparent_hsmmc(clk, clk->parent);
315}
316
317static struct clk clk_hsmmc = {
318 .name = "hsmmc-if",
319 .id = -1,
Ben Dooks9aa753c2010-01-30 09:19:59 +0200320 .parent = &clk_hsmmc_div.clk,
Ben Dookse4d06e32007-02-16 12:12:31 +0100321 .enable = s3c2443_enable_hsmmc,
Ben Dooksb3bf41b2009-12-01 01:24:37 +0000322 .ops = &(struct clk_ops) {
323 .set_parent = s3c2443_setparent_hsmmc,
324 },
Ben Dookse4d06e32007-02-16 12:12:31 +0100325};
326
327/* i2s_eplldiv
328 *
Ben Dooks9aa753c2010-01-30 09:19:59 +0200329 * This clock is the output from the I2S divisor of ESYSCLK, and is seperate
330 * from the mux that comes after it (cannot merge into one single clock)
Ben Dookse4d06e32007-02-16 12:12:31 +0100331*/
332
Ben Dooks9aa753c2010-01-30 09:19:59 +0200333static struct clksrc_clk clk_i2s_eplldiv = {
334 .clk = {
335 .name = "i2s-eplldiv",
336 .id = -1,
Ben Dooks4bed36b2010-01-30 10:25:49 +0200337 .parent = &clk_esysclk.clk,
Ben Dooksb3bf41b2009-12-01 01:24:37 +0000338 },
Ben Dooks9aa753c2010-01-30 09:19:59 +0200339 .reg_div = { .reg = S3C2443_CLKDIV1, .size = 4, .shift = 12, },
Ben Dookse4d06e32007-02-16 12:12:31 +0100340};
341
342/* i2s-ref
343 *
344 * i2s bus reference clock, selectable from external, esysclk or epllref
Ben Dooks9aa753c2010-01-30 09:19:59 +0200345 *
346 * Note, this used to be two clocks, but was compressed into one.
Ben Dookse4d06e32007-02-16 12:12:31 +0100347*/
348
Ben Dooks9aa753c2010-01-30 09:19:59 +0200349struct clk *clk_i2s_srclist[] = {
350 [0] = &clk_i2s_eplldiv.clk,
351 [1] = &clk_i2s_ext,
352 [2] = &clk_epllref.clk,
353 [3] = &clk_epllref.clk,
354};
Ben Dookse4d06e32007-02-16 12:12:31 +0100355
Ben Dooks9aa753c2010-01-30 09:19:59 +0200356static struct clksrc_clk clk_i2s = {
357 .clk = {
358 .name = "i2s-if",
359 .id = -1,
360 .ctrlbit = S3C2443_SCLKCON_I2SCLK,
361 .enable = s3c2443_clkcon_enable_s,
Ben Dookse4d06e32007-02-16 12:12:31 +0100362
Ben Dooksb3bf41b2009-12-01 01:24:37 +0000363 },
Ben Dooks9aa753c2010-01-30 09:19:59 +0200364 .sources = &(struct clksrc_sources) {
365 .sources = clk_i2s_srclist,
366 .nr_sources = ARRAY_SIZE(clk_i2s_srclist),
367 },
368 .reg_src = { .reg = S3C2443_CLKSRC, .size = 2, .shift = 14 },
Ben Dookse4d06e32007-02-16 12:12:31 +0100369};
370
371/* cam-if
372 *
373 * camera interface bus-clock, divided down from esysclk
374*/
375
Ben Dooks9aa753c2010-01-30 09:19:59 +0200376static struct clksrc_clk clk_cam = {
377 .clk = {
378 .name = "camif-upll", /* same as 2440 name */
379 .id = -1,
Ben Dooks4bed36b2010-01-30 10:25:49 +0200380 .parent = &clk_esysclk.clk,
Ben Dooks9aa753c2010-01-30 09:19:59 +0200381 .ctrlbit = S3C2443_SCLKCON_CAMCLK,
382 .enable = s3c2443_clkcon_enable_s,
Ben Dooksb3bf41b2009-12-01 01:24:37 +0000383 },
Ben Dooks9aa753c2010-01-30 09:19:59 +0200384 .reg_div = { .reg = S3C2443_CLKDIV1, .size = 4, .shift = 26 },
Ben Dookse4d06e32007-02-16 12:12:31 +0100385};
386
387/* display-if
388 *
389 * display interface clock, divided from esysclk
390*/
391
Ben Dooks9aa753c2010-01-30 09:19:59 +0200392static struct clksrc_clk clk_display = {
393 .clk = {
394 .name = "display-if",
395 .id = -1,
Ben Dooks4bed36b2010-01-30 10:25:49 +0200396 .parent = &clk_esysclk.clk,
Ben Dooks9aa753c2010-01-30 09:19:59 +0200397 .ctrlbit = S3C2443_SCLKCON_DISPCLK,
398 .enable = s3c2443_clkcon_enable_s,
Ben Dooksb3bf41b2009-12-01 01:24:37 +0000399 },
Ben Dooks9aa753c2010-01-30 09:19:59 +0200400 .reg_div = { .reg = S3C2443_CLKDIV1, .size = 8, .shift = 16 },
Ben Dookse4d06e32007-02-16 12:12:31 +0100401};
402
Ben Dooks2e16c272008-07-07 18:12:40 +0100403/* prediv
404 *
405 * this divides the msysclk down to pass to h/p/etc.
406 */
407
408static unsigned long s3c2443_prediv_getrate(struct clk *clk)
409{
410 unsigned long rate = clk_get_rate(clk->parent);
411 unsigned long clkdiv0 = __raw_readl(S3C2443_CLKDIV0);
412
413 clkdiv0 &= S3C2443_CLKDIV0_PREDIV_MASK;
414 clkdiv0 >>= S3C2443_CLKDIV0_PREDIV_SHIFT;
415
416 return rate / (clkdiv0 + 1);
417}
418
419static struct clk clk_prediv = {
420 .name = "prediv",
421 .id = -1,
Ben Dooks4bed36b2010-01-30 10:25:49 +0200422 .parent = &clk_msysclk.clk,
Ben Dooksb3bf41b2009-12-01 01:24:37 +0000423 .ops = &(struct clk_ops) {
424 .get_rate = s3c2443_prediv_getrate,
425 },
Ben Dooks2e16c272008-07-07 18:12:40 +0100426};
427
Ben Dookse4d06e32007-02-16 12:12:31 +0100428/* standard clock definitions */
429
430static struct clk init_clocks_disable[] = {
431 {
432 .name = "nand",
433 .id = -1,
434 .parent = &clk_h,
435 }, {
436 .name = "sdi",
437 .id = -1,
438 .parent = &clk_p,
439 .enable = s3c2443_clkcon_enable_p,
440 .ctrlbit = S3C2443_PCLKCON_SDI,
441 }, {
442 .name = "adc",
443 .id = -1,
444 .parent = &clk_p,
445 .enable = s3c2443_clkcon_enable_p,
446 .ctrlbit = S3C2443_PCLKCON_ADC,
447 }, {
448 .name = "i2c",
449 .id = -1,
450 .parent = &clk_p,
451 .enable = s3c2443_clkcon_enable_p,
452 .ctrlbit = S3C2443_PCLKCON_IIC,
453 }, {
454 .name = "iis",
455 .id = -1,
456 .parent = &clk_p,
457 .enable = s3c2443_clkcon_enable_p,
458 .ctrlbit = S3C2443_PCLKCON_IIS,
459 }, {
460 .name = "spi",
461 .id = 0,
462 .parent = &clk_p,
463 .enable = s3c2443_clkcon_enable_p,
464 .ctrlbit = S3C2443_PCLKCON_SPI0,
465 }, {
466 .name = "spi",
467 .id = 1,
468 .parent = &clk_p,
469 .enable = s3c2443_clkcon_enable_p,
470 .ctrlbit = S3C2443_PCLKCON_SPI1,
471 }
472};
473
474static struct clk init_clocks[] = {
475 {
476 .name = "dma",
477 .id = 0,
478 .parent = &clk_h,
479 .enable = s3c2443_clkcon_enable_h,
480 .ctrlbit = S3C2443_HCLKCON_DMA0,
481 }, {
482 .name = "dma",
483 .id = 1,
484 .parent = &clk_h,
485 .enable = s3c2443_clkcon_enable_h,
486 .ctrlbit = S3C2443_HCLKCON_DMA1,
487 }, {
488 .name = "dma",
489 .id = 2,
490 .parent = &clk_h,
491 .enable = s3c2443_clkcon_enable_h,
492 .ctrlbit = S3C2443_HCLKCON_DMA2,
493 }, {
494 .name = "dma",
495 .id = 3,
496 .parent = &clk_h,
497 .enable = s3c2443_clkcon_enable_h,
498 .ctrlbit = S3C2443_HCLKCON_DMA3,
499 }, {
500 .name = "dma",
501 .id = 4,
502 .parent = &clk_h,
503 .enable = s3c2443_clkcon_enable_h,
504 .ctrlbit = S3C2443_HCLKCON_DMA4,
505 }, {
506 .name = "dma",
507 .id = 5,
508 .parent = &clk_h,
509 .enable = s3c2443_clkcon_enable_h,
510 .ctrlbit = S3C2443_HCLKCON_DMA5,
511 }, {
512 .name = "lcd",
513 .id = -1,
514 .parent = &clk_h,
515 .enable = s3c2443_clkcon_enable_h,
516 .ctrlbit = S3C2443_HCLKCON_LCDC,
517 }, {
518 .name = "gpio",
519 .id = -1,
520 .parent = &clk_p,
521 .enable = s3c2443_clkcon_enable_p,
522 .ctrlbit = S3C2443_PCLKCON_GPIO,
523 }, {
524 .name = "usb-host",
525 .id = -1,
526 .parent = &clk_h,
527 .enable = s3c2443_clkcon_enable_h,
528 .ctrlbit = S3C2443_HCLKCON_USBH,
529 }, {
530 .name = "usb-device",
531 .id = -1,
532 .parent = &clk_h,
533 .enable = s3c2443_clkcon_enable_h,
534 .ctrlbit = S3C2443_HCLKCON_USBD,
535 }, {
Ben Dooks67364332007-05-20 17:17:32 +0100536 .name = "hsmmc",
537 .id = -1,
538 .parent = &clk_h,
539 .enable = s3c2443_clkcon_enable_h,
540 .ctrlbit = S3C2443_HCLKCON_HSMMC,
541 }, {
542 .name = "cfc",
543 .id = -1,
544 .parent = &clk_h,
545 .enable = s3c2443_clkcon_enable_h,
546 .ctrlbit = S3C2443_HCLKCON_CFC,
Ben Dooks67364332007-05-20 17:17:32 +0100547 }, {
548 .name = "ssmc",
549 .id = -1,
550 .parent = &clk_h,
551 .enable = s3c2443_clkcon_enable_h,
552 .ctrlbit = S3C2443_HCLKCON_SSMC,
553 }, {
Ben Dookse4d06e32007-02-16 12:12:31 +0100554 .name = "timers",
555 .id = -1,
556 .parent = &clk_p,
557 .enable = s3c2443_clkcon_enable_p,
558 .ctrlbit = S3C2443_PCLKCON_PWMT,
559 }, {
560 .name = "uart",
561 .id = 0,
562 .parent = &clk_p,
563 .enable = s3c2443_clkcon_enable_p,
564 .ctrlbit = S3C2443_PCLKCON_UART0,
565 }, {
566 .name = "uart",
567 .id = 1,
568 .parent = &clk_p,
569 .enable = s3c2443_clkcon_enable_p,
570 .ctrlbit = S3C2443_PCLKCON_UART1,
571 }, {
572 .name = "uart",
573 .id = 2,
574 .parent = &clk_p,
575 .enable = s3c2443_clkcon_enable_p,
576 .ctrlbit = S3C2443_PCLKCON_UART2,
577 }, {
578 .name = "uart",
579 .id = 3,
580 .parent = &clk_p,
581 .enable = s3c2443_clkcon_enable_p,
582 .ctrlbit = S3C2443_PCLKCON_UART3,
583 }, {
584 .name = "rtc",
585 .id = -1,
586 .parent = &clk_p,
587 .enable = s3c2443_clkcon_enable_p,
588 .ctrlbit = S3C2443_PCLKCON_RTC,
589 }, {
590 .name = "watchdog",
591 .id = -1,
592 .parent = &clk_p,
593 .ctrlbit = S3C2443_PCLKCON_WDT,
594 }, {
595 .name = "usb-bus-host",
596 .id = -1,
Ben Dooks9aa753c2010-01-30 09:19:59 +0200597 .parent = &clk_usb_bus_host.clk,
Ben Dooks67364332007-05-20 17:17:32 +0100598 }, {
599 .name = "ac97",
Graeme Gregoryb8b69702007-05-09 15:55:24 +0100600 .id = -1,
601 .parent = &clk_p,
602 .ctrlbit = S3C2443_PCLKCON_AC97,
Ben Dookse4d06e32007-02-16 12:12:31 +0100603 }
604};
605
606/* clocks to add where we need to check their parentage */
607
Ben Dooks9aa753c2010-01-30 09:19:59 +0200608static struct clksrc_clk __initdata *init_list[] = {
609 &clk_epllref, /* should be first */
Ben Dooks4bed36b2010-01-30 10:25:49 +0200610 &clk_esysclk,
611 &clk_msysclk,
612 &clk_arm,
Ben Dooks9aa753c2010-01-30 09:19:59 +0200613 &clk_i2s_eplldiv,
614 &clk_i2s,
615 &clk_cam,
616 &clk_uart,
617 &clk_display,
618 &clk_hsmmc_div,
619 &clk_usb_bus_host,
620};
621
Ben Dookse4d06e32007-02-16 12:12:31 +0100622static void __init s3c2443_clk_initparents(void)
623{
Ben Dooks9aa753c2010-01-30 09:19:59 +0200624 int ptr;
Ben Dookse4d06e32007-02-16 12:12:31 +0100625
Ben Dooks9aa753c2010-01-30 09:19:59 +0200626 for (ptr = 0; ptr < ARRAY_SIZE(init_list); ptr++)
Ben Dooks4bed36b2010-01-30 10:25:49 +0200627 s3c_set_clksrc(init_list[ptr], true);
Ben Dookse4d06e32007-02-16 12:12:31 +0100628}
629
630/* armdiv divisor table */
631
632static unsigned int armdiv[16] = {
633 [S3C2443_CLKDIV0_ARMDIV_1 >> S3C2443_CLKDIV0_ARMDIV_SHIFT] = 1,
634 [S3C2443_CLKDIV0_ARMDIV_2 >> S3C2443_CLKDIV0_ARMDIV_SHIFT] = 2,
635 [S3C2443_CLKDIV0_ARMDIV_3 >> S3C2443_CLKDIV0_ARMDIV_SHIFT] = 3,
636 [S3C2443_CLKDIV0_ARMDIV_4 >> S3C2443_CLKDIV0_ARMDIV_SHIFT] = 4,
637 [S3C2443_CLKDIV0_ARMDIV_6 >> S3C2443_CLKDIV0_ARMDIV_SHIFT] = 6,
638 [S3C2443_CLKDIV0_ARMDIV_8 >> S3C2443_CLKDIV0_ARMDIV_SHIFT] = 8,
639 [S3C2443_CLKDIV0_ARMDIV_12 >> S3C2443_CLKDIV0_ARMDIV_SHIFT] = 12,
640 [S3C2443_CLKDIV0_ARMDIV_16 >> S3C2443_CLKDIV0_ARMDIV_SHIFT] = 16,
641};
642
643static inline unsigned int s3c2443_fclk_div(unsigned long clkcon0)
644{
645 clkcon0 &= S3C2443_CLKDIV0_ARMDIV_MASK;
646
647 return armdiv[clkcon0 >> S3C2443_CLKDIV0_ARMDIV_SHIFT];
648}
649
Ben Dooks2e16c272008-07-07 18:12:40 +0100650static inline unsigned long s3c2443_get_hdiv(unsigned long clkcon0)
Ben Dookse4d06e32007-02-16 12:12:31 +0100651{
Ben Dooks2e16c272008-07-07 18:12:40 +0100652 clkcon0 &= S3C2443_CLKDIV0_HCLKDIV_MASK;
Ben Dookse4d06e32007-02-16 12:12:31 +0100653
654 return clkcon0 + 1;
655}
656
657/* clocks to add straight away */
658
Ben Dooks9aa753c2010-01-30 09:19:59 +0200659static struct clksrc_clk *clksrcs[] __initdata = {
Ben Dookse4d06e32007-02-16 12:12:31 +0100660 &clk_usb_bus_host,
Ben Dookse4d06e32007-02-16 12:12:31 +0100661 &clk_epllref,
Ben Dooks4bed36b2010-01-30 10:25:49 +0200662 &clk_esysclk,
663 &clk_msysclk,
664 &clk_arm,
Ben Dookse4d06e32007-02-16 12:12:31 +0100665 &clk_uart,
666 &clk_display,
667 &clk_cam,
668 &clk_i2s_eplldiv,
669 &clk_i2s,
670 &clk_hsspi,
671 &clk_hsmmc_div,
Ben Dooks9aa753c2010-01-30 09:19:59 +0200672};
673
674static struct clk *clks[] __initdata = {
675 &clk_ext,
676 &clk_epll,
677 &clk_usb_bus,
Ben Dooks9aa753c2010-01-30 09:19:59 +0200678 &clk_mpllref,
Ben Dookse4d06e32007-02-16 12:12:31 +0100679 &clk_hsmmc,
Ben Dooksba7622a2008-07-07 18:12:39 +0100680 &clk_armdiv,
Ben Dooks2e16c272008-07-07 18:12:40 +0100681 &clk_prediv,
Ben Dookse4d06e32007-02-16 12:12:31 +0100682};
683
Ben Dookse4253822008-10-21 14:06:38 +0100684void __init_or_cpufreq s3c2443_setup_clocks(void)
Ben Dookse4d06e32007-02-16 12:12:31 +0100685{
Ben Dookse4d06e32007-02-16 12:12:31 +0100686 unsigned long mpllcon = __raw_readl(S3C2443_MPLLCON);
687 unsigned long clkdiv0 = __raw_readl(S3C2443_CLKDIV0);
Ben Dookse4253822008-10-21 14:06:38 +0100688 struct clk *xtal_clk;
689 unsigned long xtal;
Ben Dookse4d06e32007-02-16 12:12:31 +0100690 unsigned long pll;
691 unsigned long fclk;
692 unsigned long hclk;
693 unsigned long pclk;
Ben Dookse4d06e32007-02-16 12:12:31 +0100694
Ben Dookse4253822008-10-21 14:06:38 +0100695 xtal_clk = clk_get(NULL, "xtal");
696 xtal = clk_get_rate(xtal_clk);
697 clk_put(xtal_clk);
Ben Dooks2e16c272008-07-07 18:12:40 +0100698
Ben Dookse4d06e32007-02-16 12:12:31 +0100699 pll = s3c2443_get_mpll(mpllcon, xtal);
Ben Dooks4bed36b2010-01-30 10:25:49 +0200700 clk_msysclk.clk.rate = pll;
Ben Dookse4d06e32007-02-16 12:12:31 +0100701
702 fclk = pll / s3c2443_fclk_div(clkdiv0);
Ben Dooks2e16c272008-07-07 18:12:40 +0100703 hclk = s3c2443_prediv_getrate(&clk_prediv);
Ben Dooks5c378662008-10-16 16:46:09 +0100704 hclk /= s3c2443_get_hdiv(clkdiv0);
Ben Dookse4d06e32007-02-16 12:12:31 +0100705 pclk = hclk / ((clkdiv0 & S3C2443_CLKDIV0_HALF_PCLK) ? 2 : 1);
706
Ben Dookse4253822008-10-21 14:06:38 +0100707 s3c24xx_setup_clocks(fclk, hclk, pclk);
Ben Dookse4d06e32007-02-16 12:12:31 +0100708
709 printk("S3C2443: mpll %s %ld.%03ld MHz, cpu %ld.%03ld MHz, mem %ld.%03ld MHz, pclk %ld.%03ld MHz\n",
710 (mpllcon & S3C2443_PLLCON_OFF) ? "off":"on",
711 print_mhz(pll), print_mhz(fclk),
712 print_mhz(hclk), print_mhz(pclk));
713
Ben Dookse4253822008-10-21 14:06:38 +0100714 s3c24xx_setup_clocks(fclk, hclk, pclk);
715}
716
717void __init s3c2443_init_clocks(int xtal)
718{
719 struct clk *clkp;
720 unsigned long epllcon = __raw_readl(S3C2443_EPLLCON);
721 int ret;
722 int ptr;
723
724 /* s3c2443 parents h and p clocks from prediv */
725 clk_h.parent = &clk_prediv;
726 clk_p.parent = &clk_prediv;
727
728 s3c24xx_register_baseclocks(xtal);
729 s3c2443_setup_clocks();
Ben Dookse4d06e32007-02-16 12:12:31 +0100730 s3c2443_clk_initparents();
731
732 for (ptr = 0; ptr < ARRAY_SIZE(clks); ptr++) {
733 clkp = clks[ptr];
734
735 ret = s3c24xx_register_clock(clkp);
736 if (ret < 0) {
737 printk(KERN_ERR "Failed to register clock %s (%d)\n",
738 clkp->name, ret);
739 }
740 }
741
Ben Dooks9aa753c2010-01-30 09:19:59 +0200742 for (ptr = 0; ptr < ARRAY_SIZE(clksrcs); ptr++)
743 s3c_register_clksrc(clksrcs[ptr], 1);
744
Ben Dookse4d06e32007-02-16 12:12:31 +0100745 clk_epll.rate = s3c2443_get_epll(epllcon, xtal);
Ben Dooks9aa753c2010-01-30 09:19:59 +0200746 clk_epll.parent = &clk_epllref.clk;
747 clk_usb_bus.parent = &clk_usb_bus_host.clk;
Ben Dookse4d06e32007-02-16 12:12:31 +0100748
749 /* ensure usb bus clock is within correct rate of 48MHz */
750
Ben Dooks9aa753c2010-01-30 09:19:59 +0200751 if (clk_get_rate(&clk_usb_bus_host.clk) != (48 * 1000 * 1000)) {
Ben Dookse4d06e32007-02-16 12:12:31 +0100752 printk(KERN_INFO "Warning: USB host bus not at 48MHz\n");
Ben Dooks9aa753c2010-01-30 09:19:59 +0200753 clk_set_rate(&clk_usb_bus_host.clk, 48*1000*1000);
Ben Dookse4d06e32007-02-16 12:12:31 +0100754 }
755
756 printk("S3C2443: epll %s %ld.%03ld MHz, usb-bus %ld.%03ld MHz\n",
757 (epllcon & S3C2443_PLLCON_OFF) ? "off":"on",
758 print_mhz(clk_get_rate(&clk_epll)),
759 print_mhz(clk_get_rate(&clk_usb_bus)));
760
761 /* register clocks from clock array */
762
Ben Dooks1d9f13c2010-01-06 01:21:38 +0900763 s3c_register_clocks(init_clocks, ARRAY_SIZE(init_clocks));
Ben Dookse4d06e32007-02-16 12:12:31 +0100764
765 /* We must be careful disabling the clocks we are not intending to
Robert P. J. Day3a4fa0a2007-10-19 23:10:43 +0200766 * be using at boot time, as subsystems such as the LCD which do
Ben Dookse4d06e32007-02-16 12:12:31 +0100767 * their own DMA requests to the bus can cause the system to lockup
768 * if they where in the middle of requesting bus access.
769 *
770 * Disabling the LCD clock if the LCD is active is very dangerous,
771 * and therefore the bootloader should be careful to not enable
772 * the LCD clock if it is not needed.
773 */
774
775 /* install (and disable) the clocks we do not need immediately */
776
777 clkp = init_clocks_disable;
778 for (ptr = 0; ptr < ARRAY_SIZE(init_clocks_disable); ptr++, clkp++) {
779
780 ret = s3c24xx_register_clock(clkp);
781 if (ret < 0) {
782 printk(KERN_ERR "Failed to register clock %s (%d)\n",
783 clkp->name, ret);
784 }
785
786 (clkp->enable)(clkp, 0);
787 }
Ben Dooks9d325f22008-11-21 10:36:05 +0000788
789 s3c_pwmclk_init();
Ben Dookse4d06e32007-02-16 12:12:31 +0100790}