clock.c revision 02239f0a4264608686cc0015d906c7b2dead89df
1/*
2 * arch/arm/mach-ep93xx/clock.c
3 * Clock control for Cirrus EP93xx chips.
4 *
5 * Copyright (C) 2006 Lennert Buytenhek <buytenh@wantstofly.org>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or (at
10 * your option) any later version.
11 */
12
13#include <linux/kernel.h>
14#include <linux/clk.h>
15#include <linux/err.h>
16#include <linux/module.h>
17#include <linux/string.h>
18#include <linux/io.h>
19
20#include <asm/clkdev.h>
21#include <asm/div64.h>
22#include <mach/hardware.h>
23
24
25/*
26 * The EP93xx has two external crystal oscillators.  To generate the
27 * required high-frequency clocks, the processor uses two phase-locked-
28 * loops (PLLs) to multiply the incoming external clock signal to much
29 * higher frequencies that are then divided down by programmable dividers
30 * to produce the needed clocks.  The PLLs operate independently of one
31 * another.
32 */
33#define EP93XX_EXT_CLK_RATE	14745600
34#define EP93XX_EXT_RTC_RATE	32768
35
36
37struct clk {
38	unsigned long	rate;
39	int		users;
40	int		sw_locked;
41	u32		enable_reg;
42	u32		enable_mask;
43
44	unsigned long	(*get_rate)(struct clk *clk);
45};
46
47
48static unsigned long get_uart_rate(struct clk *clk);
49
50
51static struct clk clk_uart1 = {
52	.sw_locked	= 1,
53	.enable_reg	= EP93XX_SYSCON_DEVCFG,
54	.enable_mask	= EP93XX_SYSCON_DEVCFG_U1EN,
55	.get_rate	= get_uart_rate,
56};
57static struct clk clk_uart2 = {
58	.sw_locked	= 1,
59	.enable_reg	= EP93XX_SYSCON_DEVCFG,
60	.enable_mask	= EP93XX_SYSCON_DEVCFG_U2EN,
61	.get_rate	= get_uart_rate,
62};
63static struct clk clk_uart3 = {
64	.sw_locked	= 1,
65	.enable_reg	= EP93XX_SYSCON_DEVCFG,
66	.enable_mask	= EP93XX_SYSCON_DEVCFG_U3EN,
67	.get_rate	= get_uart_rate,
68};
69static struct clk clk_pll1;
70static struct clk clk_f;
71static struct clk clk_h;
72static struct clk clk_p;
73static struct clk clk_pll2;
74static struct clk clk_usb_host = {
75	.enable_reg	= EP93XX_SYSCON_PWRCNT,
76	.enable_mask	= EP93XX_SYSCON_PWRCNT_USH_EN,
77};
78
79/* DMA Clocks */
80static struct clk clk_m2p0 = {
81	.enable_reg	= EP93XX_SYSCON_PWRCNT,
82	.enable_mask	= EP93XX_SYSCON_PWRCNT_DMA_M2P0,
83};
84static struct clk clk_m2p1 = {
85	.enable_reg	= EP93XX_SYSCON_PWRCNT,
86	.enable_mask	= EP93XX_SYSCON_PWRCNT_DMA_M2P1,
87};
88static struct clk clk_m2p2 = {
89	.enable_reg	= EP93XX_SYSCON_PWRCNT,
90	.enable_mask	= EP93XX_SYSCON_PWRCNT_DMA_M2P2,
91};
92static struct clk clk_m2p3 = {
93	.enable_reg	= EP93XX_SYSCON_PWRCNT,
94	.enable_mask	= EP93XX_SYSCON_PWRCNT_DMA_M2P3,
95};
96static struct clk clk_m2p4 = {
97	.enable_reg	= EP93XX_SYSCON_PWRCNT,
98	.enable_mask	= EP93XX_SYSCON_PWRCNT_DMA_M2P4,
99};
100static struct clk clk_m2p5 = {
101	.enable_reg	= EP93XX_SYSCON_PWRCNT,
102	.enable_mask	= EP93XX_SYSCON_PWRCNT_DMA_M2P5,
103};
104static struct clk clk_m2p6 = {
105	.enable_reg	= EP93XX_SYSCON_PWRCNT,
106	.enable_mask	= EP93XX_SYSCON_PWRCNT_DMA_M2P6,
107};
108static struct clk clk_m2p7 = {
109	.enable_reg	= EP93XX_SYSCON_PWRCNT,
110	.enable_mask	= EP93XX_SYSCON_PWRCNT_DMA_M2P7,
111};
112static struct clk clk_m2p8 = {
113	.enable_reg	= EP93XX_SYSCON_PWRCNT,
114	.enable_mask	= EP93XX_SYSCON_PWRCNT_DMA_M2P8,
115};
116static struct clk clk_m2p9 = {
117	.enable_reg	= EP93XX_SYSCON_PWRCNT,
118	.enable_mask	= EP93XX_SYSCON_PWRCNT_DMA_M2P9,
119};
120static struct clk clk_m2m0 = {
121	.enable_reg	= EP93XX_SYSCON_PWRCNT,
122	.enable_mask	= EP93XX_SYSCON_PWRCNT_DMA_M2M0,
123};
124static struct clk clk_m2m1 = {
125	.enable_reg	= EP93XX_SYSCON_PWRCNT,
126	.enable_mask	= EP93XX_SYSCON_PWRCNT_DMA_M2M1,
127};
128
129#define INIT_CK(dev,con,ck)					\
130	{ .dev_id = dev, .con_id = con, .clk = ck }
131
132static struct clk_lookup clocks[] = {
133	INIT_CK("apb:uart1", NULL, &clk_uart1),
134	INIT_CK("apb:uart2", NULL, &clk_uart2),
135	INIT_CK("apb:uart3", NULL, &clk_uart3),
136	INIT_CK(NULL, "pll1", &clk_pll1),
137	INIT_CK(NULL, "fclk", &clk_f),
138	INIT_CK(NULL, "hclk", &clk_h),
139	INIT_CK(NULL, "pclk", &clk_p),
140	INIT_CK(NULL, "pll2", &clk_pll2),
141	INIT_CK("ep93xx-ohci", NULL, &clk_usb_host),
142	INIT_CK(NULL, "m2p0", &clk_m2p0),
143	INIT_CK(NULL, "m2p1", &clk_m2p1),
144	INIT_CK(NULL, "m2p2", &clk_m2p2),
145	INIT_CK(NULL, "m2p3", &clk_m2p3),
146	INIT_CK(NULL, "m2p4", &clk_m2p4),
147	INIT_CK(NULL, "m2p5", &clk_m2p5),
148	INIT_CK(NULL, "m2p6", &clk_m2p6),
149	INIT_CK(NULL, "m2p7", &clk_m2p7),
150	INIT_CK(NULL, "m2p8", &clk_m2p8),
151	INIT_CK(NULL, "m2p9", &clk_m2p9),
152	INIT_CK(NULL, "m2m0", &clk_m2m0),
153	INIT_CK(NULL, "m2m1", &clk_m2m1),
154};
155
156
157int clk_enable(struct clk *clk)
158{
159	if (!clk->users++ && clk->enable_reg) {
160		u32 value;
161
162		value = __raw_readl(clk->enable_reg);
163		value |= clk->enable_mask;
164		if (clk->sw_locked)
165			ep93xx_syscon_swlocked_write(value, clk->enable_reg);
166		else
167			__raw_writel(value, clk->enable_reg);
168	}
169
170	return 0;
171}
172EXPORT_SYMBOL(clk_enable);
173
174void clk_disable(struct clk *clk)
175{
176	if (!--clk->users && clk->enable_reg) {
177		u32 value;
178
179		value = __raw_readl(clk->enable_reg);
180		value &= ~clk->enable_mask;
181		if (clk->sw_locked)
182			ep93xx_syscon_swlocked_write(value, clk->enable_reg);
183		else
184			__raw_writel(value, clk->enable_reg);
185	}
186}
187EXPORT_SYMBOL(clk_disable);
188
189static unsigned long get_uart_rate(struct clk *clk)
190{
191	u32 value;
192
193	value = __raw_readl(EP93XX_SYSCON_PWRCNT);
194	if (value & EP93XX_SYSCON_PWRCNT_UARTBAUD)
195		return EP93XX_EXT_CLK_RATE;
196	else
197		return EP93XX_EXT_CLK_RATE / 2;
198}
199
200unsigned long clk_get_rate(struct clk *clk)
201{
202	if (clk->get_rate)
203		return clk->get_rate(clk);
204
205	return clk->rate;
206}
207EXPORT_SYMBOL(clk_get_rate);
208
209
210static char fclk_divisors[] = { 1, 2, 4, 8, 16, 1, 1, 1 };
211static char hclk_divisors[] = { 1, 2, 4, 5, 6, 8, 16, 32 };
212static char pclk_divisors[] = { 1, 2, 4, 8 };
213
214/*
215 * PLL rate = 14.7456 MHz * (X1FBD + 1) * (X2FBD + 1) / (X2IPD + 1) / 2^PS
216 */
217static unsigned long calc_pll_rate(u32 config_word)
218{
219	unsigned long long rate;
220	int i;
221
222	rate = EP93XX_EXT_CLK_RATE;
223	rate *= ((config_word >> 11) & 0x1f) + 1;		/* X1FBD */
224	rate *= ((config_word >> 5) & 0x3f) + 1;		/* X2FBD */
225	do_div(rate, (config_word & 0x1f) + 1);			/* X2IPD */
226	for (i = 0; i < ((config_word >> 16) & 3); i++)		/* PS */
227		rate >>= 1;
228
229	return (unsigned long)rate;
230}
231
232static void __init ep93xx_dma_clock_init(void)
233{
234	clk_m2p0.rate = clk_h.rate;
235	clk_m2p1.rate = clk_h.rate;
236	clk_m2p2.rate = clk_h.rate;
237	clk_m2p3.rate = clk_h.rate;
238	clk_m2p4.rate = clk_h.rate;
239	clk_m2p5.rate = clk_h.rate;
240	clk_m2p6.rate = clk_h.rate;
241	clk_m2p7.rate = clk_h.rate;
242	clk_m2p8.rate = clk_h.rate;
243	clk_m2p9.rate = clk_h.rate;
244	clk_m2m0.rate = clk_h.rate;
245	clk_m2m1.rate = clk_h.rate;
246}
247
248static int __init ep93xx_clock_init(void)
249{
250	u32 value;
251	int i;
252
253	value = __raw_readl(EP93XX_SYSCON_CLOCK_SET1);
254	if (!(value & 0x00800000)) {			/* PLL1 bypassed?  */
255		clk_pll1.rate = EP93XX_EXT_CLK_RATE;
256	} else {
257		clk_pll1.rate = calc_pll_rate(value);
258	}
259	clk_f.rate = clk_pll1.rate / fclk_divisors[(value >> 25) & 0x7];
260	clk_h.rate = clk_pll1.rate / hclk_divisors[(value >> 20) & 0x7];
261	clk_p.rate = clk_h.rate / pclk_divisors[(value >> 18) & 0x3];
262	ep93xx_dma_clock_init();
263
264	value = __raw_readl(EP93XX_SYSCON_CLOCK_SET2);
265	if (!(value & 0x00080000)) {			/* PLL2 bypassed?  */
266		clk_pll2.rate = EP93XX_EXT_CLK_RATE;
267	} else if (value & 0x00040000) {		/* PLL2 enabled?  */
268		clk_pll2.rate = calc_pll_rate(value);
269	} else {
270		clk_pll2.rate = 0;
271	}
272	clk_usb_host.rate = clk_pll2.rate / (((value >> 28) & 0xf) + 1);
273
274	printk(KERN_INFO "ep93xx: PLL1 running at %ld MHz, PLL2 at %ld MHz\n",
275		clk_pll1.rate / 1000000, clk_pll2.rate / 1000000);
276	printk(KERN_INFO "ep93xx: FCLK %ld MHz, HCLK %ld MHz, PCLK %ld MHz\n",
277		clk_f.rate / 1000000, clk_h.rate / 1000000,
278		clk_p.rate / 1000000);
279
280	for (i = 0; i < ARRAY_SIZE(clocks); i++)
281		clkdev_add(&clocks[i]);
282	return 0;
283}
284arch_initcall(ep93xx_clock_init);
285