blob: 62cd4eaee01bd44a5966a08db16e1bd849579dd3 [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
Ben Dooks41f23a02010-01-30 11:14:14 +0200168/* armdiv divisor table */
169
170static unsigned int armdiv[16] = {
171 [S3C2443_CLKDIV0_ARMDIV_1 >> S3C2443_CLKDIV0_ARMDIV_SHIFT] = 1,
172 [S3C2443_CLKDIV0_ARMDIV_2 >> S3C2443_CLKDIV0_ARMDIV_SHIFT] = 2,
173 [S3C2443_CLKDIV0_ARMDIV_3 >> S3C2443_CLKDIV0_ARMDIV_SHIFT] = 3,
174 [S3C2443_CLKDIV0_ARMDIV_4 >> S3C2443_CLKDIV0_ARMDIV_SHIFT] = 4,
175 [S3C2443_CLKDIV0_ARMDIV_6 >> S3C2443_CLKDIV0_ARMDIV_SHIFT] = 6,
176 [S3C2443_CLKDIV0_ARMDIV_8 >> S3C2443_CLKDIV0_ARMDIV_SHIFT] = 8,
177 [S3C2443_CLKDIV0_ARMDIV_12 >> S3C2443_CLKDIV0_ARMDIV_SHIFT] = 12,
178 [S3C2443_CLKDIV0_ARMDIV_16 >> S3C2443_CLKDIV0_ARMDIV_SHIFT] = 16,
179};
180
181static inline unsigned int s3c2443_fclk_div(unsigned long clkcon0)
182{
183 clkcon0 &= S3C2443_CLKDIV0_ARMDIV_MASK;
184
185 return armdiv[clkcon0 >> S3C2443_CLKDIV0_ARMDIV_SHIFT];
186}
187
188static unsigned long s3c2443_armclk_roundrate(struct clk *clk,
189 unsigned long rate)
190{
191 unsigned long parent = clk_get_rate(clk->parent);
192 unsigned long calc;
193 unsigned best = 256; /* bigger than any value */
194 unsigned div;
195 int ptr;
196
197 for (ptr = 0; ptr < ARRAY_SIZE(armdiv); ptr++) {
198 div = armdiv[ptr];
199 calc = parent / div;
200 if (calc <= rate && div < best)
201 best = div;
202 }
203
204 return parent / best;
205}
206
207static int s3c2443_armclk_setrate(struct clk *clk, unsigned long rate)
208{
209 unsigned long parent = clk_get_rate(clk->parent);
210 unsigned long calc;
211 unsigned div;
212 unsigned best = 256; /* bigger than any value */
213 int ptr;
214 int val = -1;
215
216 for (ptr = 0; ptr < ARRAY_SIZE(armdiv); ptr++) {
217 div = armdiv[ptr];
218 calc = parent / div;
219 if (calc <= rate && div < best) {
220 best = div;
221 val = ptr;
222 }
223 }
224
225 if (val >= 0) {
226 unsigned long clkcon0;
227
228 clkcon0 = __raw_readl(S3C2443_CLKDIV0);
229 clkcon0 &= S3C2443_CLKDIV0_ARMDIV_MASK;
230 clkcon0 |= val << S3C2443_CLKDIV0_ARMDIV_SHIFT;
231 __raw_writel(clkcon0, S3C2443_CLKDIV0);
232 }
233
234 return (val == -1) ? -EINVAL : 0;
235}
236
Ben Dooksba7622a2008-07-07 18:12:39 +0100237static struct clk clk_armdiv = {
238 .name = "armdiv",
239 .id = -1,
Ben Dooks4bed36b2010-01-30 10:25:49 +0200240 .parent = &clk_msysclk.clk,
Ben Dooks41f23a02010-01-30 11:14:14 +0200241 .ops = &(struct clk_ops) {
242 .round_rate = s3c2443_armclk_roundrate,
243 .set_rate = s3c2443_armclk_setrate,
244 },
Ben Dooksba7622a2008-07-07 18:12:39 +0100245};
246
247/* armclk
248 *
Ben Dooks4bed36b2010-01-30 10:25:49 +0200249 * this is the clock fed into the ARM core itself, from armdiv or from hclk.
Ben Dooksba7622a2008-07-07 18:12:39 +0100250 */
251
Ben Dooks4bed36b2010-01-30 10:25:49 +0200252static struct clk *clk_arm_sources[] = {
253 [0] = &clk_armdiv,
254 [1] = &clk_h,
255};
Ben Dooksba7622a2008-07-07 18:12:39 +0100256
Ben Dooks4bed36b2010-01-30 10:25:49 +0200257static struct clksrc_clk clk_arm = {
258 .clk = {
259 .name = "armclk",
260 .id = -1,
Ben Dooksb3bf41b2009-12-01 01:24:37 +0000261 },
Ben Dooks4bed36b2010-01-30 10:25:49 +0200262 .sources = &(struct clksrc_sources) {
263 .sources = clk_arm_sources,
264 .nr_sources = ARRAY_SIZE(clk_arm_sources),
265 },
266 .reg_src = { .reg = S3C2443_CLKDIV0, .size = 1, .shift = 13 },
Ben Dooksba7622a2008-07-07 18:12:39 +0100267};
Ben Dookse4d06e32007-02-16 12:12:31 +0100268
269/* esysclk
270 *
271 * this is sourced from either the EPLL or the EPLLref clock
272*/
273
Ben Dooks4bed36b2010-01-30 10:25:49 +0200274static struct clk *clk_sysclk_sources[] = {
275 [0] = &clk_epllref.clk,
276 [1] = &clk_epll,
277};
Ben Dookse4d06e32007-02-16 12:12:31 +0100278
Ben Dooks4bed36b2010-01-30 10:25:49 +0200279static struct clksrc_clk clk_esysclk = {
280 .clk = {
281 .name = "esysclk",
282 .parent = &clk_epll,
283 .id = -1,
Ben Dooksb3bf41b2009-12-01 01:24:37 +0000284 },
Ben Dooks4bed36b2010-01-30 10:25:49 +0200285 .sources = &(struct clksrc_sources) {
286 .sources = clk_sysclk_sources,
287 .nr_sources = ARRAY_SIZE(clk_sysclk_sources),
288 },
289 .reg_src = { .reg = S3C2443_CLKSRC, .size = 1, .shift = 6 },
Ben Dookse4d06e32007-02-16 12:12:31 +0100290};
291
292/* uartclk
293 *
294 * UART baud-rate clock sourced from esysclk via a divisor
295*/
296
Ben Dooks9aa753c2010-01-30 09:19:59 +0200297static struct clksrc_clk clk_uart = {
298 .clk = {
299 .name = "uartclk",
300 .id = -1,
Ben Dooks4bed36b2010-01-30 10:25:49 +0200301 .parent = &clk_esysclk.clk,
Ben Dooksb3bf41b2009-12-01 01:24:37 +0000302 },
Ben Dooks9aa753c2010-01-30 09:19:59 +0200303 .reg_div = { .reg = S3C2443_CLKDIV1, .size = 4, .shift = 8 },
Ben Dookse4d06e32007-02-16 12:12:31 +0100304};
305
Ben Dooks9aa753c2010-01-30 09:19:59 +0200306
Ben Dookse4d06e32007-02-16 12:12:31 +0100307/* hsspi
308 *
309 * high-speed spi clock, sourced from esysclk
310*/
311
Ben Dooks9aa753c2010-01-30 09:19:59 +0200312static struct clksrc_clk clk_hsspi = {
313 .clk = {
314 .name = "hsspi",
315 .id = -1,
Ben Dooks4bed36b2010-01-30 10:25:49 +0200316 .parent = &clk_esysclk.clk,
Ben Dooks9aa753c2010-01-30 09:19:59 +0200317 .ctrlbit = S3C2443_SCLKCON_HSSPICLK,
318 .enable = s3c2443_clkcon_enable_s,
Ben Dooksb3bf41b2009-12-01 01:24:37 +0000319 },
Ben Dooks9aa753c2010-01-30 09:19:59 +0200320 .reg_div = { .reg = S3C2443_CLKDIV1, .size = 2, .shift = 4 },
Ben Dookse4d06e32007-02-16 12:12:31 +0100321};
322
323/* usbhost
324 *
325 * usb host bus-clock, usually 48MHz to provide USB bus clock timing
326*/
327
Ben Dooks9aa753c2010-01-30 09:19:59 +0200328static struct clksrc_clk clk_usb_bus_host = {
329 .clk = {
330 .name = "usb-bus-host-parent",
331 .id = -1,
Ben Dooks4bed36b2010-01-30 10:25:49 +0200332 .parent = &clk_esysclk.clk,
Ben Dooks9aa753c2010-01-30 09:19:59 +0200333 .ctrlbit = S3C2443_SCLKCON_USBHOST,
334 .enable = s3c2443_clkcon_enable_s,
Ben Dooksb3bf41b2009-12-01 01:24:37 +0000335 },
Ben Dooks9aa753c2010-01-30 09:19:59 +0200336 .reg_div = { .reg = S3C2443_CLKDIV1, .size = 2, .shift = 4 },
Ben Dookse4d06e32007-02-16 12:12:31 +0100337};
338
339/* clk_hsmcc_div
340 *
341 * this clock is sourced from epll, and is fed through a divider,
342 * to a mux controlled by sclkcon where either it or a extclk can
343 * be fed to the hsmmc block
344*/
345
Ben Dooks9aa753c2010-01-30 09:19:59 +0200346static struct clksrc_clk clk_hsmmc_div = {
347 .clk = {
348 .name = "hsmmc-div",
349 .id = -1,
Ben Dooks4bed36b2010-01-30 10:25:49 +0200350 .parent = &clk_esysclk.clk,
Ben Dooksb3bf41b2009-12-01 01:24:37 +0000351 },
Ben Dooks9aa753c2010-01-30 09:19:59 +0200352 .reg_div = { .reg = S3C2443_CLKDIV1, .size = 2, .shift = 6 },
Ben Dookse4d06e32007-02-16 12:12:31 +0100353};
354
355static int s3c2443_setparent_hsmmc(struct clk *clk, struct clk *parent)
356{
357 unsigned long clksrc = __raw_readl(S3C2443_SCLKCON);
358
359 clksrc &= ~(S3C2443_SCLKCON_HSMMCCLK_EXT |
360 S3C2443_SCLKCON_HSMMCCLK_EPLL);
361
362 if (parent == &clk_epll)
363 clksrc |= S3C2443_SCLKCON_HSMMCCLK_EPLL;
364 else if (parent == &clk_ext)
365 clksrc |= S3C2443_SCLKCON_HSMMCCLK_EXT;
366 else
367 return -EINVAL;
368
369 if (clk->usage > 0) {
370 __raw_writel(clksrc, S3C2443_SCLKCON);
371 }
372
373 clk->parent = parent;
374 return 0;
375}
376
377static int s3c2443_enable_hsmmc(struct clk *clk, int enable)
378{
379 return s3c2443_setparent_hsmmc(clk, clk->parent);
380}
381
382static struct clk clk_hsmmc = {
383 .name = "hsmmc-if",
384 .id = -1,
Ben Dooks9aa753c2010-01-30 09:19:59 +0200385 .parent = &clk_hsmmc_div.clk,
Ben Dookse4d06e32007-02-16 12:12:31 +0100386 .enable = s3c2443_enable_hsmmc,
Ben Dooksb3bf41b2009-12-01 01:24:37 +0000387 .ops = &(struct clk_ops) {
388 .set_parent = s3c2443_setparent_hsmmc,
389 },
Ben Dookse4d06e32007-02-16 12:12:31 +0100390};
391
392/* i2s_eplldiv
393 *
Ben Dooks9aa753c2010-01-30 09:19:59 +0200394 * This clock is the output from the I2S divisor of ESYSCLK, and is seperate
395 * from the mux that comes after it (cannot merge into one single clock)
Ben Dookse4d06e32007-02-16 12:12:31 +0100396*/
397
Ben Dooks9aa753c2010-01-30 09:19:59 +0200398static struct clksrc_clk clk_i2s_eplldiv = {
399 .clk = {
400 .name = "i2s-eplldiv",
401 .id = -1,
Ben Dooks4bed36b2010-01-30 10:25:49 +0200402 .parent = &clk_esysclk.clk,
Ben Dooksb3bf41b2009-12-01 01:24:37 +0000403 },
Ben Dooks9aa753c2010-01-30 09:19:59 +0200404 .reg_div = { .reg = S3C2443_CLKDIV1, .size = 4, .shift = 12, },
Ben Dookse4d06e32007-02-16 12:12:31 +0100405};
406
407/* i2s-ref
408 *
409 * i2s bus reference clock, selectable from external, esysclk or epllref
Ben Dooks9aa753c2010-01-30 09:19:59 +0200410 *
411 * Note, this used to be two clocks, but was compressed into one.
Ben Dookse4d06e32007-02-16 12:12:31 +0100412*/
413
Ben Dooks9aa753c2010-01-30 09:19:59 +0200414struct clk *clk_i2s_srclist[] = {
415 [0] = &clk_i2s_eplldiv.clk,
416 [1] = &clk_i2s_ext,
417 [2] = &clk_epllref.clk,
418 [3] = &clk_epllref.clk,
419};
Ben Dookse4d06e32007-02-16 12:12:31 +0100420
Ben Dooks9aa753c2010-01-30 09:19:59 +0200421static struct clksrc_clk clk_i2s = {
422 .clk = {
423 .name = "i2s-if",
424 .id = -1,
425 .ctrlbit = S3C2443_SCLKCON_I2SCLK,
426 .enable = s3c2443_clkcon_enable_s,
Ben Dookse4d06e32007-02-16 12:12:31 +0100427
Ben Dooksb3bf41b2009-12-01 01:24:37 +0000428 },
Ben Dooks9aa753c2010-01-30 09:19:59 +0200429 .sources = &(struct clksrc_sources) {
430 .sources = clk_i2s_srclist,
431 .nr_sources = ARRAY_SIZE(clk_i2s_srclist),
432 },
433 .reg_src = { .reg = S3C2443_CLKSRC, .size = 2, .shift = 14 },
Ben Dookse4d06e32007-02-16 12:12:31 +0100434};
435
436/* cam-if
437 *
438 * camera interface bus-clock, divided down from esysclk
439*/
440
Ben Dooks9aa753c2010-01-30 09:19:59 +0200441static struct clksrc_clk clk_cam = {
442 .clk = {
443 .name = "camif-upll", /* same as 2440 name */
444 .id = -1,
Ben Dooks4bed36b2010-01-30 10:25:49 +0200445 .parent = &clk_esysclk.clk,
Ben Dooks9aa753c2010-01-30 09:19:59 +0200446 .ctrlbit = S3C2443_SCLKCON_CAMCLK,
447 .enable = s3c2443_clkcon_enable_s,
Ben Dooksb3bf41b2009-12-01 01:24:37 +0000448 },
Ben Dooks9aa753c2010-01-30 09:19:59 +0200449 .reg_div = { .reg = S3C2443_CLKDIV1, .size = 4, .shift = 26 },
Ben Dookse4d06e32007-02-16 12:12:31 +0100450};
451
452/* display-if
453 *
454 * display interface clock, divided from esysclk
455*/
456
Ben Dooks9aa753c2010-01-30 09:19:59 +0200457static struct clksrc_clk clk_display = {
458 .clk = {
459 .name = "display-if",
460 .id = -1,
Ben Dooks4bed36b2010-01-30 10:25:49 +0200461 .parent = &clk_esysclk.clk,
Ben Dooks9aa753c2010-01-30 09:19:59 +0200462 .ctrlbit = S3C2443_SCLKCON_DISPCLK,
463 .enable = s3c2443_clkcon_enable_s,
Ben Dooksb3bf41b2009-12-01 01:24:37 +0000464 },
Ben Dooks9aa753c2010-01-30 09:19:59 +0200465 .reg_div = { .reg = S3C2443_CLKDIV1, .size = 8, .shift = 16 },
Ben Dookse4d06e32007-02-16 12:12:31 +0100466};
467
Ben Dooks2e16c272008-07-07 18:12:40 +0100468/* prediv
469 *
470 * this divides the msysclk down to pass to h/p/etc.
471 */
472
473static unsigned long s3c2443_prediv_getrate(struct clk *clk)
474{
475 unsigned long rate = clk_get_rate(clk->parent);
476 unsigned long clkdiv0 = __raw_readl(S3C2443_CLKDIV0);
477
478 clkdiv0 &= S3C2443_CLKDIV0_PREDIV_MASK;
479 clkdiv0 >>= S3C2443_CLKDIV0_PREDIV_SHIFT;
480
481 return rate / (clkdiv0 + 1);
482}
483
484static struct clk clk_prediv = {
485 .name = "prediv",
486 .id = -1,
Ben Dooks4bed36b2010-01-30 10:25:49 +0200487 .parent = &clk_msysclk.clk,
Ben Dooksb3bf41b2009-12-01 01:24:37 +0000488 .ops = &(struct clk_ops) {
489 .get_rate = s3c2443_prediv_getrate,
490 },
Ben Dooks2e16c272008-07-07 18:12:40 +0100491};
492
Ben Dookse4d06e32007-02-16 12:12:31 +0100493/* standard clock definitions */
494
495static struct clk init_clocks_disable[] = {
496 {
497 .name = "nand",
498 .id = -1,
499 .parent = &clk_h,
500 }, {
501 .name = "sdi",
502 .id = -1,
503 .parent = &clk_p,
504 .enable = s3c2443_clkcon_enable_p,
505 .ctrlbit = S3C2443_PCLKCON_SDI,
506 }, {
507 .name = "adc",
508 .id = -1,
509 .parent = &clk_p,
510 .enable = s3c2443_clkcon_enable_p,
511 .ctrlbit = S3C2443_PCLKCON_ADC,
512 }, {
513 .name = "i2c",
514 .id = -1,
515 .parent = &clk_p,
516 .enable = s3c2443_clkcon_enable_p,
517 .ctrlbit = S3C2443_PCLKCON_IIC,
518 }, {
519 .name = "iis",
520 .id = -1,
521 .parent = &clk_p,
522 .enable = s3c2443_clkcon_enable_p,
523 .ctrlbit = S3C2443_PCLKCON_IIS,
524 }, {
525 .name = "spi",
526 .id = 0,
527 .parent = &clk_p,
528 .enable = s3c2443_clkcon_enable_p,
529 .ctrlbit = S3C2443_PCLKCON_SPI0,
530 }, {
531 .name = "spi",
532 .id = 1,
533 .parent = &clk_p,
534 .enable = s3c2443_clkcon_enable_p,
535 .ctrlbit = S3C2443_PCLKCON_SPI1,
536 }
537};
538
539static struct clk init_clocks[] = {
540 {
541 .name = "dma",
542 .id = 0,
543 .parent = &clk_h,
544 .enable = s3c2443_clkcon_enable_h,
545 .ctrlbit = S3C2443_HCLKCON_DMA0,
546 }, {
547 .name = "dma",
548 .id = 1,
549 .parent = &clk_h,
550 .enable = s3c2443_clkcon_enable_h,
551 .ctrlbit = S3C2443_HCLKCON_DMA1,
552 }, {
553 .name = "dma",
554 .id = 2,
555 .parent = &clk_h,
556 .enable = s3c2443_clkcon_enable_h,
557 .ctrlbit = S3C2443_HCLKCON_DMA2,
558 }, {
559 .name = "dma",
560 .id = 3,
561 .parent = &clk_h,
562 .enable = s3c2443_clkcon_enable_h,
563 .ctrlbit = S3C2443_HCLKCON_DMA3,
564 }, {
565 .name = "dma",
566 .id = 4,
567 .parent = &clk_h,
568 .enable = s3c2443_clkcon_enable_h,
569 .ctrlbit = S3C2443_HCLKCON_DMA4,
570 }, {
571 .name = "dma",
572 .id = 5,
573 .parent = &clk_h,
574 .enable = s3c2443_clkcon_enable_h,
575 .ctrlbit = S3C2443_HCLKCON_DMA5,
576 }, {
577 .name = "lcd",
578 .id = -1,
579 .parent = &clk_h,
580 .enable = s3c2443_clkcon_enable_h,
581 .ctrlbit = S3C2443_HCLKCON_LCDC,
582 }, {
583 .name = "gpio",
584 .id = -1,
585 .parent = &clk_p,
586 .enable = s3c2443_clkcon_enable_p,
587 .ctrlbit = S3C2443_PCLKCON_GPIO,
588 }, {
589 .name = "usb-host",
590 .id = -1,
591 .parent = &clk_h,
592 .enable = s3c2443_clkcon_enable_h,
593 .ctrlbit = S3C2443_HCLKCON_USBH,
594 }, {
595 .name = "usb-device",
596 .id = -1,
597 .parent = &clk_h,
598 .enable = s3c2443_clkcon_enable_h,
599 .ctrlbit = S3C2443_HCLKCON_USBD,
600 }, {
Ben Dooks67364332007-05-20 17:17:32 +0100601 .name = "hsmmc",
602 .id = -1,
603 .parent = &clk_h,
604 .enable = s3c2443_clkcon_enable_h,
605 .ctrlbit = S3C2443_HCLKCON_HSMMC,
606 }, {
607 .name = "cfc",
608 .id = -1,
609 .parent = &clk_h,
610 .enable = s3c2443_clkcon_enable_h,
611 .ctrlbit = S3C2443_HCLKCON_CFC,
Ben Dooks67364332007-05-20 17:17:32 +0100612 }, {
613 .name = "ssmc",
614 .id = -1,
615 .parent = &clk_h,
616 .enable = s3c2443_clkcon_enable_h,
617 .ctrlbit = S3C2443_HCLKCON_SSMC,
618 }, {
Ben Dookse4d06e32007-02-16 12:12:31 +0100619 .name = "timers",
620 .id = -1,
621 .parent = &clk_p,
622 .enable = s3c2443_clkcon_enable_p,
623 .ctrlbit = S3C2443_PCLKCON_PWMT,
624 }, {
625 .name = "uart",
626 .id = 0,
627 .parent = &clk_p,
628 .enable = s3c2443_clkcon_enable_p,
629 .ctrlbit = S3C2443_PCLKCON_UART0,
630 }, {
631 .name = "uart",
632 .id = 1,
633 .parent = &clk_p,
634 .enable = s3c2443_clkcon_enable_p,
635 .ctrlbit = S3C2443_PCLKCON_UART1,
636 }, {
637 .name = "uart",
638 .id = 2,
639 .parent = &clk_p,
640 .enable = s3c2443_clkcon_enable_p,
641 .ctrlbit = S3C2443_PCLKCON_UART2,
642 }, {
643 .name = "uart",
644 .id = 3,
645 .parent = &clk_p,
646 .enable = s3c2443_clkcon_enable_p,
647 .ctrlbit = S3C2443_PCLKCON_UART3,
648 }, {
649 .name = "rtc",
650 .id = -1,
651 .parent = &clk_p,
652 .enable = s3c2443_clkcon_enable_p,
653 .ctrlbit = S3C2443_PCLKCON_RTC,
654 }, {
655 .name = "watchdog",
656 .id = -1,
657 .parent = &clk_p,
658 .ctrlbit = S3C2443_PCLKCON_WDT,
659 }, {
660 .name = "usb-bus-host",
661 .id = -1,
Ben Dooks9aa753c2010-01-30 09:19:59 +0200662 .parent = &clk_usb_bus_host.clk,
Ben Dooks67364332007-05-20 17:17:32 +0100663 }, {
664 .name = "ac97",
Graeme Gregoryb8b69702007-05-09 15:55:24 +0100665 .id = -1,
666 .parent = &clk_p,
667 .ctrlbit = S3C2443_PCLKCON_AC97,
Ben Dookse4d06e32007-02-16 12:12:31 +0100668 }
669};
670
671/* clocks to add where we need to check their parentage */
672
Ben Dooks9aa753c2010-01-30 09:19:59 +0200673static struct clksrc_clk __initdata *init_list[] = {
674 &clk_epllref, /* should be first */
Ben Dooks4bed36b2010-01-30 10:25:49 +0200675 &clk_esysclk,
676 &clk_msysclk,
677 &clk_arm,
Ben Dooks9aa753c2010-01-30 09:19:59 +0200678 &clk_i2s_eplldiv,
679 &clk_i2s,
680 &clk_cam,
681 &clk_uart,
682 &clk_display,
683 &clk_hsmmc_div,
684 &clk_usb_bus_host,
685};
686
Ben Dookse4d06e32007-02-16 12:12:31 +0100687static void __init s3c2443_clk_initparents(void)
688{
Ben Dooks9aa753c2010-01-30 09:19:59 +0200689 int ptr;
Ben Dookse4d06e32007-02-16 12:12:31 +0100690
Ben Dooks9aa753c2010-01-30 09:19:59 +0200691 for (ptr = 0; ptr < ARRAY_SIZE(init_list); ptr++)
Ben Dooks4bed36b2010-01-30 10:25:49 +0200692 s3c_set_clksrc(init_list[ptr], true);
Ben Dookse4d06e32007-02-16 12:12:31 +0100693}
694
Ben Dooks2e16c272008-07-07 18:12:40 +0100695static inline unsigned long s3c2443_get_hdiv(unsigned long clkcon0)
Ben Dookse4d06e32007-02-16 12:12:31 +0100696{
Ben Dooks2e16c272008-07-07 18:12:40 +0100697 clkcon0 &= S3C2443_CLKDIV0_HCLKDIV_MASK;
Ben Dookse4d06e32007-02-16 12:12:31 +0100698
699 return clkcon0 + 1;
700}
701
702/* clocks to add straight away */
703
Ben Dooks9aa753c2010-01-30 09:19:59 +0200704static struct clksrc_clk *clksrcs[] __initdata = {
Ben Dookse4d06e32007-02-16 12:12:31 +0100705 &clk_usb_bus_host,
Ben Dookse4d06e32007-02-16 12:12:31 +0100706 &clk_epllref,
Ben Dooks4bed36b2010-01-30 10:25:49 +0200707 &clk_esysclk,
708 &clk_msysclk,
709 &clk_arm,
Ben Dookse4d06e32007-02-16 12:12:31 +0100710 &clk_uart,
711 &clk_display,
712 &clk_cam,
713 &clk_i2s_eplldiv,
714 &clk_i2s,
715 &clk_hsspi,
716 &clk_hsmmc_div,
Ben Dooks9aa753c2010-01-30 09:19:59 +0200717};
718
719static struct clk *clks[] __initdata = {
720 &clk_ext,
721 &clk_epll,
722 &clk_usb_bus,
Ben Dooks9aa753c2010-01-30 09:19:59 +0200723 &clk_mpllref,
Ben Dookse4d06e32007-02-16 12:12:31 +0100724 &clk_hsmmc,
Ben Dooksba7622a2008-07-07 18:12:39 +0100725 &clk_armdiv,
Ben Dooks2e16c272008-07-07 18:12:40 +0100726 &clk_prediv,
Ben Dookse4d06e32007-02-16 12:12:31 +0100727};
728
Ben Dookse4253822008-10-21 14:06:38 +0100729void __init_or_cpufreq s3c2443_setup_clocks(void)
Ben Dookse4d06e32007-02-16 12:12:31 +0100730{
Ben Dookse4d06e32007-02-16 12:12:31 +0100731 unsigned long mpllcon = __raw_readl(S3C2443_MPLLCON);
732 unsigned long clkdiv0 = __raw_readl(S3C2443_CLKDIV0);
Ben Dookse4253822008-10-21 14:06:38 +0100733 struct clk *xtal_clk;
734 unsigned long xtal;
Ben Dookse4d06e32007-02-16 12:12:31 +0100735 unsigned long pll;
736 unsigned long fclk;
737 unsigned long hclk;
738 unsigned long pclk;
Ben Dookse4d06e32007-02-16 12:12:31 +0100739
Ben Dookse4253822008-10-21 14:06:38 +0100740 xtal_clk = clk_get(NULL, "xtal");
741 xtal = clk_get_rate(xtal_clk);
742 clk_put(xtal_clk);
Ben Dooks2e16c272008-07-07 18:12:40 +0100743
Ben Dookse4d06e32007-02-16 12:12:31 +0100744 pll = s3c2443_get_mpll(mpllcon, xtal);
Ben Dooks4bed36b2010-01-30 10:25:49 +0200745 clk_msysclk.clk.rate = pll;
Ben Dookse4d06e32007-02-16 12:12:31 +0100746
747 fclk = pll / s3c2443_fclk_div(clkdiv0);
Ben Dooks2e16c272008-07-07 18:12:40 +0100748 hclk = s3c2443_prediv_getrate(&clk_prediv);
Ben Dooks5c378662008-10-16 16:46:09 +0100749 hclk /= s3c2443_get_hdiv(clkdiv0);
Ben Dookse4d06e32007-02-16 12:12:31 +0100750 pclk = hclk / ((clkdiv0 & S3C2443_CLKDIV0_HALF_PCLK) ? 2 : 1);
751
Ben Dookse4253822008-10-21 14:06:38 +0100752 s3c24xx_setup_clocks(fclk, hclk, pclk);
Ben Dookse4d06e32007-02-16 12:12:31 +0100753
754 printk("S3C2443: mpll %s %ld.%03ld MHz, cpu %ld.%03ld MHz, mem %ld.%03ld MHz, pclk %ld.%03ld MHz\n",
755 (mpllcon & S3C2443_PLLCON_OFF) ? "off":"on",
756 print_mhz(pll), print_mhz(fclk),
757 print_mhz(hclk), print_mhz(pclk));
758
Ben Dookse4253822008-10-21 14:06:38 +0100759 s3c24xx_setup_clocks(fclk, hclk, pclk);
760}
761
762void __init s3c2443_init_clocks(int xtal)
763{
764 struct clk *clkp;
765 unsigned long epllcon = __raw_readl(S3C2443_EPLLCON);
766 int ret;
767 int ptr;
768
769 /* s3c2443 parents h and p clocks from prediv */
770 clk_h.parent = &clk_prediv;
771 clk_p.parent = &clk_prediv;
772
773 s3c24xx_register_baseclocks(xtal);
774 s3c2443_setup_clocks();
Ben Dookse4d06e32007-02-16 12:12:31 +0100775 s3c2443_clk_initparents();
776
777 for (ptr = 0; ptr < ARRAY_SIZE(clks); ptr++) {
778 clkp = clks[ptr];
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
Ben Dooks9aa753c2010-01-30 09:19:59 +0200787 for (ptr = 0; ptr < ARRAY_SIZE(clksrcs); ptr++)
788 s3c_register_clksrc(clksrcs[ptr], 1);
789
Ben Dookse4d06e32007-02-16 12:12:31 +0100790 clk_epll.rate = s3c2443_get_epll(epllcon, xtal);
Ben Dooks9aa753c2010-01-30 09:19:59 +0200791 clk_epll.parent = &clk_epllref.clk;
792 clk_usb_bus.parent = &clk_usb_bus_host.clk;
Ben Dookse4d06e32007-02-16 12:12:31 +0100793
794 /* ensure usb bus clock is within correct rate of 48MHz */
795
Ben Dooks9aa753c2010-01-30 09:19:59 +0200796 if (clk_get_rate(&clk_usb_bus_host.clk) != (48 * 1000 * 1000)) {
Ben Dookse4d06e32007-02-16 12:12:31 +0100797 printk(KERN_INFO "Warning: USB host bus not at 48MHz\n");
Ben Dooks9aa753c2010-01-30 09:19:59 +0200798 clk_set_rate(&clk_usb_bus_host.clk, 48*1000*1000);
Ben Dookse4d06e32007-02-16 12:12:31 +0100799 }
800
801 printk("S3C2443: epll %s %ld.%03ld MHz, usb-bus %ld.%03ld MHz\n",
802 (epllcon & S3C2443_PLLCON_OFF) ? "off":"on",
803 print_mhz(clk_get_rate(&clk_epll)),
804 print_mhz(clk_get_rate(&clk_usb_bus)));
805
806 /* register clocks from clock array */
807
Ben Dooks1d9f13c2010-01-06 01:21:38 +0900808 s3c_register_clocks(init_clocks, ARRAY_SIZE(init_clocks));
Ben Dookse4d06e32007-02-16 12:12:31 +0100809
810 /* We must be careful disabling the clocks we are not intending to
Robert P. J. Day3a4fa0a2007-10-19 23:10:43 +0200811 * be using at boot time, as subsystems such as the LCD which do
Ben Dookse4d06e32007-02-16 12:12:31 +0100812 * their own DMA requests to the bus can cause the system to lockup
813 * if they where in the middle of requesting bus access.
814 *
815 * Disabling the LCD clock if the LCD is active is very dangerous,
816 * and therefore the bootloader should be careful to not enable
817 * the LCD clock if it is not needed.
818 */
819
820 /* install (and disable) the clocks we do not need immediately */
821
822 clkp = init_clocks_disable;
823 for (ptr = 0; ptr < ARRAY_SIZE(init_clocks_disable); ptr++, clkp++) {
824
825 ret = s3c24xx_register_clock(clkp);
826 if (ret < 0) {
827 printk(KERN_ERR "Failed to register clock %s (%d)\n",
828 clkp->name, ret);
829 }
830
831 (clkp->enable)(clkp, 0);
832 }
Ben Dooks9d325f22008-11-21 10:36:05 +0000833
834 s3c_pwmclk_init();
Ben Dookse4d06e32007-02-16 12:12:31 +0100835}