blob: 177719c7c267b1d68d06236f2729ef00f0899b5e [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
Ben Dookse4d06e32007-02-16 12:12:31 +010098static struct clk clk_i2s_ext = {
99 .name = "i2s-ext",
100 .id = -1,
101};
102
Ben Dooks9aa753c2010-01-30 09:19:59 +0200103static struct clk *clk_epllref_sources[] = {
104 [0] = &clk_mpllref,
105 [1] = &clk_mpllref,
106 [2] = &clk_xtal,
107 [3] = &clk_ext,
108};
Ben Dookse4d06e32007-02-16 12:12:31 +0100109
Ben Dooks9aa753c2010-01-30 09:19:59 +0200110static struct clksrc_clk clk_epllref = {
111 .clk = {
112 .name = "epllref",
113 .id = -1,
Ben Dooksb3bf41b2009-12-01 01:24:37 +0000114 },
Ben Dooks9aa753c2010-01-30 09:19:59 +0200115 .sources = &(struct clksrc_sources) {
116 .sources = clk_epllref_sources,
117 .nr_sources = ARRAY_SIZE(clk_epllref_sources),
118 },
119 .reg_src = { .reg = S3C2443_CLKSRC, .size = 2, .shift = 7 },
Ben Dookse4d06e32007-02-16 12:12:31 +0100120};
121
122static unsigned long s3c2443_getrate_mdivclk(struct clk *clk)
123{
124 unsigned long parent_rate = clk_get_rate(clk->parent);
125 unsigned long div = __raw_readl(S3C2443_CLKDIV0);
126
127 div &= S3C2443_CLKDIV0_EXTDIV_MASK;
128 div >>= (S3C2443_CLKDIV0_EXTDIV_SHIFT-1); /* x2 */
129
130 return parent_rate / (div + 1);
131}
132
133static struct clk clk_mdivclk = {
134 .name = "mdivclk",
135 .parent = &clk_mpllref,
136 .id = -1,
Ben Dooksb3bf41b2009-12-01 01:24:37 +0000137 .ops = &(struct clk_ops) {
138 .get_rate = s3c2443_getrate_mdivclk,
139 },
Ben Dookse4d06e32007-02-16 12:12:31 +0100140};
141
Ben Dooks4bed36b2010-01-30 10:25:49 +0200142static struct clk *clk_msysclk_sources[] = {
143 [0] = &clk_mpllref,
144 [1] = &clk_mpll,
145 [2] = &clk_mdivclk,
146 [3] = &clk_mpllref,
147};
Ben Dookse4d06e32007-02-16 12:12:31 +0100148
Ben Dooks4bed36b2010-01-30 10:25:49 +0200149static struct clksrc_clk clk_msysclk = {
150 .clk = {
151 .name = "msysclk",
152 .parent = &clk_xtal,
153 .id = -1,
Ben Dooksb3bf41b2009-12-01 01:24:37 +0000154 },
Ben Dooks4bed36b2010-01-30 10:25:49 +0200155 .sources = &(struct clksrc_sources) {
156 .sources = clk_msysclk_sources,
157 .nr_sources = ARRAY_SIZE(clk_msysclk_sources),
158 },
159 .reg_src = { .reg = S3C2443_CLKSRC, .size = 2, .shift = 3 },
Ben Dookse4d06e32007-02-16 12:12:31 +0100160};
161
Ben Dooksba7622a2008-07-07 18:12:39 +0100162/* armdiv
163 *
164 * this clock is sourced from msysclk and can have a number of
165 * divider values applied to it to then be fed into armclk.
166*/
167
168static struct clk clk_armdiv = {
169 .name = "armdiv",
170 .id = -1,
Ben Dooks4bed36b2010-01-30 10:25:49 +0200171 .parent = &clk_msysclk.clk,
Ben Dooksba7622a2008-07-07 18:12:39 +0100172};
173
174/* armclk
175 *
Ben Dooks4bed36b2010-01-30 10:25:49 +0200176 * this is the clock fed into the ARM core itself, from armdiv or from hclk.
Ben Dooksba7622a2008-07-07 18:12:39 +0100177 */
178
Ben Dooks4bed36b2010-01-30 10:25:49 +0200179static struct clk *clk_arm_sources[] = {
180 [0] = &clk_armdiv,
181 [1] = &clk_h,
182};
Ben Dooksba7622a2008-07-07 18:12:39 +0100183
Ben Dooks4bed36b2010-01-30 10:25:49 +0200184static struct clksrc_clk clk_arm = {
185 .clk = {
186 .name = "armclk",
187 .id = -1,
Ben Dooksb3bf41b2009-12-01 01:24:37 +0000188 },
Ben Dooks4bed36b2010-01-30 10:25:49 +0200189 .sources = &(struct clksrc_sources) {
190 .sources = clk_arm_sources,
191 .nr_sources = ARRAY_SIZE(clk_arm_sources),
192 },
193 .reg_src = { .reg = S3C2443_CLKDIV0, .size = 1, .shift = 13 },
Ben Dooksba7622a2008-07-07 18:12:39 +0100194};
Ben Dookse4d06e32007-02-16 12:12:31 +0100195
196/* esysclk
197 *
198 * this is sourced from either the EPLL or the EPLLref clock
199*/
200
Ben Dooks4bed36b2010-01-30 10:25:49 +0200201static struct clk *clk_sysclk_sources[] = {
202 [0] = &clk_epllref.clk,
203 [1] = &clk_epll,
204};
Ben Dookse4d06e32007-02-16 12:12:31 +0100205
Ben Dooks4bed36b2010-01-30 10:25:49 +0200206static struct clksrc_clk clk_esysclk = {
207 .clk = {
208 .name = "esysclk",
209 .parent = &clk_epll,
210 .id = -1,
Ben Dooksb3bf41b2009-12-01 01:24:37 +0000211 },
Ben Dooks4bed36b2010-01-30 10:25:49 +0200212 .sources = &(struct clksrc_sources) {
213 .sources = clk_sysclk_sources,
214 .nr_sources = ARRAY_SIZE(clk_sysclk_sources),
215 },
216 .reg_src = { .reg = S3C2443_CLKSRC, .size = 1, .shift = 6 },
Ben Dookse4d06e32007-02-16 12:12:31 +0100217};
218
219/* uartclk
220 *
221 * UART baud-rate clock sourced from esysclk via a divisor
222*/
223
Ben Dooks9aa753c2010-01-30 09:19:59 +0200224static struct clksrc_clk clk_uart = {
225 .clk = {
226 .name = "uartclk",
227 .id = -1,
Ben Dooks4bed36b2010-01-30 10:25:49 +0200228 .parent = &clk_esysclk.clk,
Ben Dooksb3bf41b2009-12-01 01:24:37 +0000229 },
Ben Dooks9aa753c2010-01-30 09:19:59 +0200230 .reg_div = { .reg = S3C2443_CLKDIV1, .size = 4, .shift = 8 },
Ben Dookse4d06e32007-02-16 12:12:31 +0100231};
232
Ben Dooks9aa753c2010-01-30 09:19:59 +0200233
Ben Dookse4d06e32007-02-16 12:12:31 +0100234/* hsspi
235 *
236 * high-speed spi clock, sourced from esysclk
237*/
238
Ben Dooks9aa753c2010-01-30 09:19:59 +0200239static struct clksrc_clk clk_hsspi = {
240 .clk = {
241 .name = "hsspi",
242 .id = -1,
Ben Dooks4bed36b2010-01-30 10:25:49 +0200243 .parent = &clk_esysclk.clk,
Ben Dooks9aa753c2010-01-30 09:19:59 +0200244 .ctrlbit = S3C2443_SCLKCON_HSSPICLK,
245 .enable = s3c2443_clkcon_enable_s,
Ben Dooksb3bf41b2009-12-01 01:24:37 +0000246 },
Ben Dooks9aa753c2010-01-30 09:19:59 +0200247 .reg_div = { .reg = S3C2443_CLKDIV1, .size = 2, .shift = 4 },
Ben Dookse4d06e32007-02-16 12:12:31 +0100248};
249
250/* usbhost
251 *
252 * usb host bus-clock, usually 48MHz to provide USB bus clock timing
253*/
254
Ben Dooks9aa753c2010-01-30 09:19:59 +0200255static struct clksrc_clk clk_usb_bus_host = {
256 .clk = {
257 .name = "usb-bus-host-parent",
258 .id = -1,
Ben Dooks4bed36b2010-01-30 10:25:49 +0200259 .parent = &clk_esysclk.clk,
Ben Dooks9aa753c2010-01-30 09:19:59 +0200260 .ctrlbit = S3C2443_SCLKCON_USBHOST,
261 .enable = s3c2443_clkcon_enable_s,
Ben Dooksb3bf41b2009-12-01 01:24:37 +0000262 },
Ben Dooks9aa753c2010-01-30 09:19:59 +0200263 .reg_div = { .reg = S3C2443_CLKDIV1, .size = 2, .shift = 4 },
Ben Dookse4d06e32007-02-16 12:12:31 +0100264};
265
266/* clk_hsmcc_div
267 *
268 * this clock is sourced from epll, and is fed through a divider,
269 * to a mux controlled by sclkcon where either it or a extclk can
270 * be fed to the hsmmc block
271*/
272
Ben Dooks9aa753c2010-01-30 09:19:59 +0200273static struct clksrc_clk clk_hsmmc_div = {
274 .clk = {
275 .name = "hsmmc-div",
276 .id = -1,
Ben Dooks4bed36b2010-01-30 10:25:49 +0200277 .parent = &clk_esysclk.clk,
Ben Dooksb3bf41b2009-12-01 01:24:37 +0000278 },
Ben Dooks9aa753c2010-01-30 09:19:59 +0200279 .reg_div = { .reg = S3C2443_CLKDIV1, .size = 2, .shift = 6 },
Ben Dookse4d06e32007-02-16 12:12:31 +0100280};
281
282static int s3c2443_setparent_hsmmc(struct clk *clk, struct clk *parent)
283{
284 unsigned long clksrc = __raw_readl(S3C2443_SCLKCON);
285
286 clksrc &= ~(S3C2443_SCLKCON_HSMMCCLK_EXT |
287 S3C2443_SCLKCON_HSMMCCLK_EPLL);
288
289 if (parent == &clk_epll)
290 clksrc |= S3C2443_SCLKCON_HSMMCCLK_EPLL;
291 else if (parent == &clk_ext)
292 clksrc |= S3C2443_SCLKCON_HSMMCCLK_EXT;
293 else
294 return -EINVAL;
295
296 if (clk->usage > 0) {
297 __raw_writel(clksrc, S3C2443_SCLKCON);
298 }
299
300 clk->parent = parent;
301 return 0;
302}
303
304static int s3c2443_enable_hsmmc(struct clk *clk, int enable)
305{
306 return s3c2443_setparent_hsmmc(clk, clk->parent);
307}
308
309static struct clk clk_hsmmc = {
310 .name = "hsmmc-if",
311 .id = -1,
Ben Dooks9aa753c2010-01-30 09:19:59 +0200312 .parent = &clk_hsmmc_div.clk,
Ben Dookse4d06e32007-02-16 12:12:31 +0100313 .enable = s3c2443_enable_hsmmc,
Ben Dooksb3bf41b2009-12-01 01:24:37 +0000314 .ops = &(struct clk_ops) {
315 .set_parent = s3c2443_setparent_hsmmc,
316 },
Ben Dookse4d06e32007-02-16 12:12:31 +0100317};
318
319/* i2s_eplldiv
320 *
Ben Dooks9aa753c2010-01-30 09:19:59 +0200321 * This clock is the output from the I2S divisor of ESYSCLK, and is seperate
322 * from the mux that comes after it (cannot merge into one single clock)
Ben Dookse4d06e32007-02-16 12:12:31 +0100323*/
324
Ben Dooks9aa753c2010-01-30 09:19:59 +0200325static struct clksrc_clk clk_i2s_eplldiv = {
326 .clk = {
327 .name = "i2s-eplldiv",
328 .id = -1,
Ben Dooks4bed36b2010-01-30 10:25:49 +0200329 .parent = &clk_esysclk.clk,
Ben Dooksb3bf41b2009-12-01 01:24:37 +0000330 },
Ben Dooks9aa753c2010-01-30 09:19:59 +0200331 .reg_div = { .reg = S3C2443_CLKDIV1, .size = 4, .shift = 12, },
Ben Dookse4d06e32007-02-16 12:12:31 +0100332};
333
334/* i2s-ref
335 *
336 * i2s bus reference clock, selectable from external, esysclk or epllref
Ben Dooks9aa753c2010-01-30 09:19:59 +0200337 *
338 * Note, this used to be two clocks, but was compressed into one.
Ben Dookse4d06e32007-02-16 12:12:31 +0100339*/
340
Ben Dooks9aa753c2010-01-30 09:19:59 +0200341struct clk *clk_i2s_srclist[] = {
342 [0] = &clk_i2s_eplldiv.clk,
343 [1] = &clk_i2s_ext,
344 [2] = &clk_epllref.clk,
345 [3] = &clk_epllref.clk,
346};
Ben Dookse4d06e32007-02-16 12:12:31 +0100347
Ben Dooks9aa753c2010-01-30 09:19:59 +0200348static struct clksrc_clk clk_i2s = {
349 .clk = {
350 .name = "i2s-if",
351 .id = -1,
352 .ctrlbit = S3C2443_SCLKCON_I2SCLK,
353 .enable = s3c2443_clkcon_enable_s,
Ben Dookse4d06e32007-02-16 12:12:31 +0100354
Ben Dooksb3bf41b2009-12-01 01:24:37 +0000355 },
Ben Dooks9aa753c2010-01-30 09:19:59 +0200356 .sources = &(struct clksrc_sources) {
357 .sources = clk_i2s_srclist,
358 .nr_sources = ARRAY_SIZE(clk_i2s_srclist),
359 },
360 .reg_src = { .reg = S3C2443_CLKSRC, .size = 2, .shift = 14 },
Ben Dookse4d06e32007-02-16 12:12:31 +0100361};
362
363/* cam-if
364 *
365 * camera interface bus-clock, divided down from esysclk
366*/
367
Ben Dooks9aa753c2010-01-30 09:19:59 +0200368static struct clksrc_clk clk_cam = {
369 .clk = {
370 .name = "camif-upll", /* same as 2440 name */
371 .id = -1,
Ben Dooks4bed36b2010-01-30 10:25:49 +0200372 .parent = &clk_esysclk.clk,
Ben Dooks9aa753c2010-01-30 09:19:59 +0200373 .ctrlbit = S3C2443_SCLKCON_CAMCLK,
374 .enable = s3c2443_clkcon_enable_s,
Ben Dooksb3bf41b2009-12-01 01:24:37 +0000375 },
Ben Dooks9aa753c2010-01-30 09:19:59 +0200376 .reg_div = { .reg = S3C2443_CLKDIV1, .size = 4, .shift = 26 },
Ben Dookse4d06e32007-02-16 12:12:31 +0100377};
378
379/* display-if
380 *
381 * display interface clock, divided from esysclk
382*/
383
Ben Dooks9aa753c2010-01-30 09:19:59 +0200384static struct clksrc_clk clk_display = {
385 .clk = {
386 .name = "display-if",
387 .id = -1,
Ben Dooks4bed36b2010-01-30 10:25:49 +0200388 .parent = &clk_esysclk.clk,
Ben Dooks9aa753c2010-01-30 09:19:59 +0200389 .ctrlbit = S3C2443_SCLKCON_DISPCLK,
390 .enable = s3c2443_clkcon_enable_s,
Ben Dooksb3bf41b2009-12-01 01:24:37 +0000391 },
Ben Dooks9aa753c2010-01-30 09:19:59 +0200392 .reg_div = { .reg = S3C2443_CLKDIV1, .size = 8, .shift = 16 },
Ben Dookse4d06e32007-02-16 12:12:31 +0100393};
394
Ben Dooks2e16c272008-07-07 18:12:40 +0100395/* prediv
396 *
397 * this divides the msysclk down to pass to h/p/etc.
398 */
399
400static unsigned long s3c2443_prediv_getrate(struct clk *clk)
401{
402 unsigned long rate = clk_get_rate(clk->parent);
403 unsigned long clkdiv0 = __raw_readl(S3C2443_CLKDIV0);
404
405 clkdiv0 &= S3C2443_CLKDIV0_PREDIV_MASK;
406 clkdiv0 >>= S3C2443_CLKDIV0_PREDIV_SHIFT;
407
408 return rate / (clkdiv0 + 1);
409}
410
411static struct clk clk_prediv = {
412 .name = "prediv",
413 .id = -1,
Ben Dooks4bed36b2010-01-30 10:25:49 +0200414 .parent = &clk_msysclk.clk,
Ben Dooksb3bf41b2009-12-01 01:24:37 +0000415 .ops = &(struct clk_ops) {
416 .get_rate = s3c2443_prediv_getrate,
417 },
Ben Dooks2e16c272008-07-07 18:12:40 +0100418};
419
Ben Dookse4d06e32007-02-16 12:12:31 +0100420/* standard clock definitions */
421
422static struct clk init_clocks_disable[] = {
423 {
424 .name = "nand",
425 .id = -1,
426 .parent = &clk_h,
427 }, {
428 .name = "sdi",
429 .id = -1,
430 .parent = &clk_p,
431 .enable = s3c2443_clkcon_enable_p,
432 .ctrlbit = S3C2443_PCLKCON_SDI,
433 }, {
434 .name = "adc",
435 .id = -1,
436 .parent = &clk_p,
437 .enable = s3c2443_clkcon_enable_p,
438 .ctrlbit = S3C2443_PCLKCON_ADC,
439 }, {
440 .name = "i2c",
441 .id = -1,
442 .parent = &clk_p,
443 .enable = s3c2443_clkcon_enable_p,
444 .ctrlbit = S3C2443_PCLKCON_IIC,
445 }, {
446 .name = "iis",
447 .id = -1,
448 .parent = &clk_p,
449 .enable = s3c2443_clkcon_enable_p,
450 .ctrlbit = S3C2443_PCLKCON_IIS,
451 }, {
452 .name = "spi",
453 .id = 0,
454 .parent = &clk_p,
455 .enable = s3c2443_clkcon_enable_p,
456 .ctrlbit = S3C2443_PCLKCON_SPI0,
457 }, {
458 .name = "spi",
459 .id = 1,
460 .parent = &clk_p,
461 .enable = s3c2443_clkcon_enable_p,
462 .ctrlbit = S3C2443_PCLKCON_SPI1,
463 }
464};
465
466static struct clk init_clocks[] = {
467 {
468 .name = "dma",
469 .id = 0,
470 .parent = &clk_h,
471 .enable = s3c2443_clkcon_enable_h,
472 .ctrlbit = S3C2443_HCLKCON_DMA0,
473 }, {
474 .name = "dma",
475 .id = 1,
476 .parent = &clk_h,
477 .enable = s3c2443_clkcon_enable_h,
478 .ctrlbit = S3C2443_HCLKCON_DMA1,
479 }, {
480 .name = "dma",
481 .id = 2,
482 .parent = &clk_h,
483 .enable = s3c2443_clkcon_enable_h,
484 .ctrlbit = S3C2443_HCLKCON_DMA2,
485 }, {
486 .name = "dma",
487 .id = 3,
488 .parent = &clk_h,
489 .enable = s3c2443_clkcon_enable_h,
490 .ctrlbit = S3C2443_HCLKCON_DMA3,
491 }, {
492 .name = "dma",
493 .id = 4,
494 .parent = &clk_h,
495 .enable = s3c2443_clkcon_enable_h,
496 .ctrlbit = S3C2443_HCLKCON_DMA4,
497 }, {
498 .name = "dma",
499 .id = 5,
500 .parent = &clk_h,
501 .enable = s3c2443_clkcon_enable_h,
502 .ctrlbit = S3C2443_HCLKCON_DMA5,
503 }, {
504 .name = "lcd",
505 .id = -1,
506 .parent = &clk_h,
507 .enable = s3c2443_clkcon_enable_h,
508 .ctrlbit = S3C2443_HCLKCON_LCDC,
509 }, {
510 .name = "gpio",
511 .id = -1,
512 .parent = &clk_p,
513 .enable = s3c2443_clkcon_enable_p,
514 .ctrlbit = S3C2443_PCLKCON_GPIO,
515 }, {
516 .name = "usb-host",
517 .id = -1,
518 .parent = &clk_h,
519 .enable = s3c2443_clkcon_enable_h,
520 .ctrlbit = S3C2443_HCLKCON_USBH,
521 }, {
522 .name = "usb-device",
523 .id = -1,
524 .parent = &clk_h,
525 .enable = s3c2443_clkcon_enable_h,
526 .ctrlbit = S3C2443_HCLKCON_USBD,
527 }, {
Ben Dooks67364332007-05-20 17:17:32 +0100528 .name = "hsmmc",
529 .id = -1,
530 .parent = &clk_h,
531 .enable = s3c2443_clkcon_enable_h,
532 .ctrlbit = S3C2443_HCLKCON_HSMMC,
533 }, {
534 .name = "cfc",
535 .id = -1,
536 .parent = &clk_h,
537 .enable = s3c2443_clkcon_enable_h,
538 .ctrlbit = S3C2443_HCLKCON_CFC,
Ben Dooks67364332007-05-20 17:17:32 +0100539 }, {
540 .name = "ssmc",
541 .id = -1,
542 .parent = &clk_h,
543 .enable = s3c2443_clkcon_enable_h,
544 .ctrlbit = S3C2443_HCLKCON_SSMC,
545 }, {
Ben Dookse4d06e32007-02-16 12:12:31 +0100546 .name = "timers",
547 .id = -1,
548 .parent = &clk_p,
549 .enable = s3c2443_clkcon_enable_p,
550 .ctrlbit = S3C2443_PCLKCON_PWMT,
551 }, {
552 .name = "uart",
553 .id = 0,
554 .parent = &clk_p,
555 .enable = s3c2443_clkcon_enable_p,
556 .ctrlbit = S3C2443_PCLKCON_UART0,
557 }, {
558 .name = "uart",
559 .id = 1,
560 .parent = &clk_p,
561 .enable = s3c2443_clkcon_enable_p,
562 .ctrlbit = S3C2443_PCLKCON_UART1,
563 }, {
564 .name = "uart",
565 .id = 2,
566 .parent = &clk_p,
567 .enable = s3c2443_clkcon_enable_p,
568 .ctrlbit = S3C2443_PCLKCON_UART2,
569 }, {
570 .name = "uart",
571 .id = 3,
572 .parent = &clk_p,
573 .enable = s3c2443_clkcon_enable_p,
574 .ctrlbit = S3C2443_PCLKCON_UART3,
575 }, {
576 .name = "rtc",
577 .id = -1,
578 .parent = &clk_p,
579 .enable = s3c2443_clkcon_enable_p,
580 .ctrlbit = S3C2443_PCLKCON_RTC,
581 }, {
582 .name = "watchdog",
583 .id = -1,
584 .parent = &clk_p,
585 .ctrlbit = S3C2443_PCLKCON_WDT,
586 }, {
587 .name = "usb-bus-host",
588 .id = -1,
Ben Dooks9aa753c2010-01-30 09:19:59 +0200589 .parent = &clk_usb_bus_host.clk,
Ben Dooks67364332007-05-20 17:17:32 +0100590 }, {
591 .name = "ac97",
Graeme Gregoryb8b69702007-05-09 15:55:24 +0100592 .id = -1,
593 .parent = &clk_p,
594 .ctrlbit = S3C2443_PCLKCON_AC97,
Ben Dookse4d06e32007-02-16 12:12:31 +0100595 }
596};
597
598/* clocks to add where we need to check their parentage */
599
Ben Dooks9aa753c2010-01-30 09:19:59 +0200600static struct clksrc_clk __initdata *init_list[] = {
601 &clk_epllref, /* should be first */
Ben Dooks4bed36b2010-01-30 10:25:49 +0200602 &clk_esysclk,
603 &clk_msysclk,
604 &clk_arm,
Ben Dooks9aa753c2010-01-30 09:19:59 +0200605 &clk_i2s_eplldiv,
606 &clk_i2s,
607 &clk_cam,
608 &clk_uart,
609 &clk_display,
610 &clk_hsmmc_div,
611 &clk_usb_bus_host,
612};
613
Ben Dookse4d06e32007-02-16 12:12:31 +0100614static void __init s3c2443_clk_initparents(void)
615{
Ben Dooks9aa753c2010-01-30 09:19:59 +0200616 int ptr;
Ben Dookse4d06e32007-02-16 12:12:31 +0100617
Ben Dooks9aa753c2010-01-30 09:19:59 +0200618 for (ptr = 0; ptr < ARRAY_SIZE(init_list); ptr++)
Ben Dooks4bed36b2010-01-30 10:25:49 +0200619 s3c_set_clksrc(init_list[ptr], true);
Ben Dookse4d06e32007-02-16 12:12:31 +0100620}
621
622/* armdiv divisor table */
623
624static unsigned int armdiv[16] = {
625 [S3C2443_CLKDIV0_ARMDIV_1 >> S3C2443_CLKDIV0_ARMDIV_SHIFT] = 1,
626 [S3C2443_CLKDIV0_ARMDIV_2 >> S3C2443_CLKDIV0_ARMDIV_SHIFT] = 2,
627 [S3C2443_CLKDIV0_ARMDIV_3 >> S3C2443_CLKDIV0_ARMDIV_SHIFT] = 3,
628 [S3C2443_CLKDIV0_ARMDIV_4 >> S3C2443_CLKDIV0_ARMDIV_SHIFT] = 4,
629 [S3C2443_CLKDIV0_ARMDIV_6 >> S3C2443_CLKDIV0_ARMDIV_SHIFT] = 6,
630 [S3C2443_CLKDIV0_ARMDIV_8 >> S3C2443_CLKDIV0_ARMDIV_SHIFT] = 8,
631 [S3C2443_CLKDIV0_ARMDIV_12 >> S3C2443_CLKDIV0_ARMDIV_SHIFT] = 12,
632 [S3C2443_CLKDIV0_ARMDIV_16 >> S3C2443_CLKDIV0_ARMDIV_SHIFT] = 16,
633};
634
635static inline unsigned int s3c2443_fclk_div(unsigned long clkcon0)
636{
637 clkcon0 &= S3C2443_CLKDIV0_ARMDIV_MASK;
638
639 return armdiv[clkcon0 >> S3C2443_CLKDIV0_ARMDIV_SHIFT];
640}
641
Ben Dooks2e16c272008-07-07 18:12:40 +0100642static inline unsigned long s3c2443_get_hdiv(unsigned long clkcon0)
Ben Dookse4d06e32007-02-16 12:12:31 +0100643{
Ben Dooks2e16c272008-07-07 18:12:40 +0100644 clkcon0 &= S3C2443_CLKDIV0_HCLKDIV_MASK;
Ben Dookse4d06e32007-02-16 12:12:31 +0100645
646 return clkcon0 + 1;
647}
648
649/* clocks to add straight away */
650
Ben Dooks9aa753c2010-01-30 09:19:59 +0200651static struct clksrc_clk *clksrcs[] __initdata = {
Ben Dookse4d06e32007-02-16 12:12:31 +0100652 &clk_usb_bus_host,
Ben Dookse4d06e32007-02-16 12:12:31 +0100653 &clk_epllref,
Ben Dooks4bed36b2010-01-30 10:25:49 +0200654 &clk_esysclk,
655 &clk_msysclk,
656 &clk_arm,
Ben Dookse4d06e32007-02-16 12:12:31 +0100657 &clk_uart,
658 &clk_display,
659 &clk_cam,
660 &clk_i2s_eplldiv,
661 &clk_i2s,
662 &clk_hsspi,
663 &clk_hsmmc_div,
Ben Dooks9aa753c2010-01-30 09:19:59 +0200664};
665
666static struct clk *clks[] __initdata = {
667 &clk_ext,
668 &clk_epll,
669 &clk_usb_bus,
Ben Dooks9aa753c2010-01-30 09:19:59 +0200670 &clk_mpllref,
Ben Dookse4d06e32007-02-16 12:12:31 +0100671 &clk_hsmmc,
Ben Dooksba7622a2008-07-07 18:12:39 +0100672 &clk_armdiv,
Ben Dooks2e16c272008-07-07 18:12:40 +0100673 &clk_prediv,
Ben Dookse4d06e32007-02-16 12:12:31 +0100674};
675
Ben Dookse4253822008-10-21 14:06:38 +0100676void __init_or_cpufreq s3c2443_setup_clocks(void)
Ben Dookse4d06e32007-02-16 12:12:31 +0100677{
Ben Dookse4d06e32007-02-16 12:12:31 +0100678 unsigned long mpllcon = __raw_readl(S3C2443_MPLLCON);
679 unsigned long clkdiv0 = __raw_readl(S3C2443_CLKDIV0);
Ben Dookse4253822008-10-21 14:06:38 +0100680 struct clk *xtal_clk;
681 unsigned long xtal;
Ben Dookse4d06e32007-02-16 12:12:31 +0100682 unsigned long pll;
683 unsigned long fclk;
684 unsigned long hclk;
685 unsigned long pclk;
Ben Dookse4d06e32007-02-16 12:12:31 +0100686
Ben Dookse4253822008-10-21 14:06:38 +0100687 xtal_clk = clk_get(NULL, "xtal");
688 xtal = clk_get_rate(xtal_clk);
689 clk_put(xtal_clk);
Ben Dooks2e16c272008-07-07 18:12:40 +0100690
Ben Dookse4d06e32007-02-16 12:12:31 +0100691 pll = s3c2443_get_mpll(mpllcon, xtal);
Ben Dooks4bed36b2010-01-30 10:25:49 +0200692 clk_msysclk.clk.rate = pll;
Ben Dookse4d06e32007-02-16 12:12:31 +0100693
694 fclk = pll / s3c2443_fclk_div(clkdiv0);
Ben Dooks2e16c272008-07-07 18:12:40 +0100695 hclk = s3c2443_prediv_getrate(&clk_prediv);
Ben Dooks5c378662008-10-16 16:46:09 +0100696 hclk /= s3c2443_get_hdiv(clkdiv0);
Ben Dookse4d06e32007-02-16 12:12:31 +0100697 pclk = hclk / ((clkdiv0 & S3C2443_CLKDIV0_HALF_PCLK) ? 2 : 1);
698
Ben Dookse4253822008-10-21 14:06:38 +0100699 s3c24xx_setup_clocks(fclk, hclk, pclk);
Ben Dookse4d06e32007-02-16 12:12:31 +0100700
701 printk("S3C2443: mpll %s %ld.%03ld MHz, cpu %ld.%03ld MHz, mem %ld.%03ld MHz, pclk %ld.%03ld MHz\n",
702 (mpllcon & S3C2443_PLLCON_OFF) ? "off":"on",
703 print_mhz(pll), print_mhz(fclk),
704 print_mhz(hclk), print_mhz(pclk));
705
Ben Dookse4253822008-10-21 14:06:38 +0100706 s3c24xx_setup_clocks(fclk, hclk, pclk);
707}
708
709void __init s3c2443_init_clocks(int xtal)
710{
711 struct clk *clkp;
712 unsigned long epllcon = __raw_readl(S3C2443_EPLLCON);
713 int ret;
714 int ptr;
715
716 /* s3c2443 parents h and p clocks from prediv */
717 clk_h.parent = &clk_prediv;
718 clk_p.parent = &clk_prediv;
719
720 s3c24xx_register_baseclocks(xtal);
721 s3c2443_setup_clocks();
Ben Dookse4d06e32007-02-16 12:12:31 +0100722 s3c2443_clk_initparents();
723
724 for (ptr = 0; ptr < ARRAY_SIZE(clks); ptr++) {
725 clkp = clks[ptr];
726
727 ret = s3c24xx_register_clock(clkp);
728 if (ret < 0) {
729 printk(KERN_ERR "Failed to register clock %s (%d)\n",
730 clkp->name, ret);
731 }
732 }
733
Ben Dooks9aa753c2010-01-30 09:19:59 +0200734 for (ptr = 0; ptr < ARRAY_SIZE(clksrcs); ptr++)
735 s3c_register_clksrc(clksrcs[ptr], 1);
736
Ben Dookse4d06e32007-02-16 12:12:31 +0100737 clk_epll.rate = s3c2443_get_epll(epllcon, xtal);
Ben Dooks9aa753c2010-01-30 09:19:59 +0200738 clk_epll.parent = &clk_epllref.clk;
739 clk_usb_bus.parent = &clk_usb_bus_host.clk;
Ben Dookse4d06e32007-02-16 12:12:31 +0100740
741 /* ensure usb bus clock is within correct rate of 48MHz */
742
Ben Dooks9aa753c2010-01-30 09:19:59 +0200743 if (clk_get_rate(&clk_usb_bus_host.clk) != (48 * 1000 * 1000)) {
Ben Dookse4d06e32007-02-16 12:12:31 +0100744 printk(KERN_INFO "Warning: USB host bus not at 48MHz\n");
Ben Dooks9aa753c2010-01-30 09:19:59 +0200745 clk_set_rate(&clk_usb_bus_host.clk, 48*1000*1000);
Ben Dookse4d06e32007-02-16 12:12:31 +0100746 }
747
748 printk("S3C2443: epll %s %ld.%03ld MHz, usb-bus %ld.%03ld MHz\n",
749 (epllcon & S3C2443_PLLCON_OFF) ? "off":"on",
750 print_mhz(clk_get_rate(&clk_epll)),
751 print_mhz(clk_get_rate(&clk_usb_bus)));
752
753 /* register clocks from clock array */
754
Ben Dooks1d9f13c2010-01-06 01:21:38 +0900755 s3c_register_clocks(init_clocks, ARRAY_SIZE(init_clocks));
Ben Dookse4d06e32007-02-16 12:12:31 +0100756
757 /* We must be careful disabling the clocks we are not intending to
Robert P. J. Day3a4fa0a2007-10-19 23:10:43 +0200758 * be using at boot time, as subsystems such as the LCD which do
Ben Dookse4d06e32007-02-16 12:12:31 +0100759 * their own DMA requests to the bus can cause the system to lockup
760 * if they where in the middle of requesting bus access.
761 *
762 * Disabling the LCD clock if the LCD is active is very dangerous,
763 * and therefore the bootloader should be careful to not enable
764 * the LCD clock if it is not needed.
765 */
766
767 /* install (and disable) the clocks we do not need immediately */
768
769 clkp = init_clocks_disable;
770 for (ptr = 0; ptr < ARRAY_SIZE(init_clocks_disable); ptr++, clkp++) {
771
772 ret = s3c24xx_register_clock(clkp);
773 if (ret < 0) {
774 printk(KERN_ERR "Failed to register clock %s (%d)\n",
775 clkp->name, ret);
776 }
777
778 (clkp->enable)(clkp, 0);
779 }
Ben Dooks9d325f22008-11-21 10:36:05 +0000780
781 s3c_pwmclk_init();
Ben Dookse4d06e32007-02-16 12:12:31 +0100782}