diff options
Diffstat (limited to 'arch/arm/mach-ep93xx/clock.c')
-rw-r--r-- | arch/arm/mach-ep93xx/clock.c | 123 |
1 files changed, 88 insertions, 35 deletions
diff --git a/arch/arm/mach-ep93xx/clock.c b/arch/arm/mach-ep93xx/clock.c index e8ebeaea6c48..6c4c1633ed12 100644 --- a/arch/arm/mach-ep93xx/clock.c +++ b/arch/arm/mach-ep93xx/clock.c | |||
@@ -21,15 +21,50 @@ | |||
21 | #include <asm/div64.h> | 21 | #include <asm/div64.h> |
22 | #include <mach/hardware.h> | 22 | #include <mach/hardware.h> |
23 | 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 | |||
24 | struct clk { | 37 | struct clk { |
25 | unsigned long rate; | 38 | unsigned long rate; |
26 | int users; | 39 | int users; |
40 | int sw_locked; | ||
27 | u32 enable_reg; | 41 | u32 enable_reg; |
28 | u32 enable_mask; | 42 | u32 enable_mask; |
43 | |||
44 | unsigned long (*get_rate)(struct clk *clk); | ||
29 | }; | 45 | }; |
30 | 46 | ||
31 | static struct clk clk_uart = { | 47 | |
32 | .rate = 14745600, | 48 | static unsigned long get_uart_rate(struct clk *clk); |
49 | |||
50 | |||
51 | static struct clk clk_uart1 = { | ||
52 | .sw_locked = 1, | ||
53 | .enable_reg = EP93XX_SYSCON_DEVICE_CONFIG, | ||
54 | .enable_mask = EP93XX_SYSCON_DEVICE_CONFIG_U1EN, | ||
55 | .get_rate = get_uart_rate, | ||
56 | }; | ||
57 | static struct clk clk_uart2 = { | ||
58 | .sw_locked = 1, | ||
59 | .enable_reg = EP93XX_SYSCON_DEVICE_CONFIG, | ||
60 | .enable_mask = EP93XX_SYSCON_DEVICE_CONFIG_U2EN, | ||
61 | .get_rate = get_uart_rate, | ||
62 | }; | ||
63 | static struct clk clk_uart3 = { | ||
64 | .sw_locked = 1, | ||
65 | .enable_reg = EP93XX_SYSCON_DEVICE_CONFIG, | ||
66 | .enable_mask = EP93XX_SYSCON_DEVICE_CONFIG_U3EN, | ||
67 | .get_rate = get_uart_rate, | ||
33 | }; | 68 | }; |
34 | static struct clk clk_pll1; | 69 | static struct clk clk_pll1; |
35 | static struct clk clk_f; | 70 | static struct clk clk_f; |
@@ -37,73 +72,73 @@ static struct clk clk_h; | |||
37 | static struct clk clk_p; | 72 | static struct clk clk_p; |
38 | static struct clk clk_pll2; | 73 | static struct clk clk_pll2; |
39 | static struct clk clk_usb_host = { | 74 | static struct clk clk_usb_host = { |
40 | .enable_reg = EP93XX_SYSCON_CLOCK_CONTROL, | 75 | .enable_reg = EP93XX_SYSCON_PWRCNT, |
41 | .enable_mask = EP93XX_SYSCON_CLOCK_USH_EN, | 76 | .enable_mask = EP93XX_SYSCON_PWRCNT_USH_EN, |
42 | }; | 77 | }; |
43 | 78 | ||
44 | /* DMA Clocks */ | 79 | /* DMA Clocks */ |
45 | static struct clk clk_m2p0 = { | 80 | static struct clk clk_m2p0 = { |
46 | .enable_reg = EP93XX_SYSCON_CLOCK_CONTROL, | 81 | .enable_reg = EP93XX_SYSCON_PWRCNT, |
47 | .enable_mask = 0x00020000, | 82 | .enable_mask = EP93XX_SYSCON_PWRCNT_DMA_M2P0, |
48 | }; | 83 | }; |
49 | static struct clk clk_m2p1 = { | 84 | static struct clk clk_m2p1 = { |
50 | .enable_reg = EP93XX_SYSCON_CLOCK_CONTROL, | 85 | .enable_reg = EP93XX_SYSCON_PWRCNT, |
51 | .enable_mask = 0x00010000, | 86 | .enable_mask = EP93XX_SYSCON_PWRCNT_DMA_M2P1, |
52 | }; | 87 | }; |
53 | static struct clk clk_m2p2 = { | 88 | static struct clk clk_m2p2 = { |
54 | .enable_reg = EP93XX_SYSCON_CLOCK_CONTROL, | 89 | .enable_reg = EP93XX_SYSCON_PWRCNT, |
55 | .enable_mask = 0x00080000, | 90 | .enable_mask = EP93XX_SYSCON_PWRCNT_DMA_M2P2, |
56 | }; | 91 | }; |
57 | static struct clk clk_m2p3 = { | 92 | static struct clk clk_m2p3 = { |
58 | .enable_reg = EP93XX_SYSCON_CLOCK_CONTROL, | 93 | .enable_reg = EP93XX_SYSCON_PWRCNT, |
59 | .enable_mask = 0x00040000, | 94 | .enable_mask = EP93XX_SYSCON_PWRCNT_DMA_M2P3, |
60 | }; | 95 | }; |
61 | static struct clk clk_m2p4 = { | 96 | static struct clk clk_m2p4 = { |
62 | .enable_reg = EP93XX_SYSCON_CLOCK_CONTROL, | 97 | .enable_reg = EP93XX_SYSCON_PWRCNT, |
63 | .enable_mask = 0x00200000, | 98 | .enable_mask = EP93XX_SYSCON_PWRCNT_DMA_M2P4, |
64 | }; | 99 | }; |
65 | static struct clk clk_m2p5 = { | 100 | static struct clk clk_m2p5 = { |
66 | .enable_reg = EP93XX_SYSCON_CLOCK_CONTROL, | 101 | .enable_reg = EP93XX_SYSCON_PWRCNT, |
67 | .enable_mask = 0x00100000, | 102 | .enable_mask = EP93XX_SYSCON_PWRCNT_DMA_M2P5, |
68 | }; | 103 | }; |
69 | static struct clk clk_m2p6 = { | 104 | static struct clk clk_m2p6 = { |
70 | .enable_reg = EP93XX_SYSCON_CLOCK_CONTROL, | 105 | .enable_reg = EP93XX_SYSCON_PWRCNT, |
71 | .enable_mask = 0x00800000, | 106 | .enable_mask = EP93XX_SYSCON_PWRCNT_DMA_M2P6, |
72 | }; | 107 | }; |
73 | static struct clk clk_m2p7 = { | 108 | static struct clk clk_m2p7 = { |
74 | .enable_reg = EP93XX_SYSCON_CLOCK_CONTROL, | 109 | .enable_reg = EP93XX_SYSCON_PWRCNT, |
75 | .enable_mask = 0x00400000, | 110 | .enable_mask = EP93XX_SYSCON_PWRCNT_DMA_M2P7, |
76 | }; | 111 | }; |
77 | static struct clk clk_m2p8 = { | 112 | static struct clk clk_m2p8 = { |
78 | .enable_reg = EP93XX_SYSCON_CLOCK_CONTROL, | 113 | .enable_reg = EP93XX_SYSCON_PWRCNT, |
79 | .enable_mask = 0x02000000, | 114 | .enable_mask = EP93XX_SYSCON_PWRCNT_DMA_M2P8, |
80 | }; | 115 | }; |
81 | static struct clk clk_m2p9 = { | 116 | static struct clk clk_m2p9 = { |
82 | .enable_reg = EP93XX_SYSCON_CLOCK_CONTROL, | 117 | .enable_reg = EP93XX_SYSCON_PWRCNT, |
83 | .enable_mask = 0x01000000, | 118 | .enable_mask = EP93XX_SYSCON_PWRCNT_DMA_M2P9, |
84 | }; | 119 | }; |
85 | static struct clk clk_m2m0 = { | 120 | static struct clk clk_m2m0 = { |
86 | .enable_reg = EP93XX_SYSCON_CLOCK_CONTROL, | 121 | .enable_reg = EP93XX_SYSCON_PWRCNT, |
87 | .enable_mask = 0x04000000, | 122 | .enable_mask = EP93XX_SYSCON_PWRCNT_DMA_M2M0, |
88 | }; | 123 | }; |
89 | static struct clk clk_m2m1 = { | 124 | static struct clk clk_m2m1 = { |
90 | .enable_reg = EP93XX_SYSCON_CLOCK_CONTROL, | 125 | .enable_reg = EP93XX_SYSCON_PWRCNT, |
91 | .enable_mask = 0x08000000, | 126 | .enable_mask = EP93XX_SYSCON_PWRCNT_DMA_M2M1, |
92 | }; | 127 | }; |
93 | 128 | ||
94 | #define INIT_CK(dev,con,ck) \ | 129 | #define INIT_CK(dev,con,ck) \ |
95 | { .dev_id = dev, .con_id = con, .clk = ck } | 130 | { .dev_id = dev, .con_id = con, .clk = ck } |
96 | 131 | ||
97 | static struct clk_lookup clocks[] = { | 132 | static struct clk_lookup clocks[] = { |
98 | INIT_CK("apb:uart1", NULL, &clk_uart), | 133 | INIT_CK("apb:uart1", NULL, &clk_uart1), |
99 | INIT_CK("apb:uart2", NULL, &clk_uart), | 134 | INIT_CK("apb:uart2", NULL, &clk_uart2), |
100 | INIT_CK("apb:uart3", NULL, &clk_uart), | 135 | INIT_CK("apb:uart3", NULL, &clk_uart3), |
101 | INIT_CK(NULL, "pll1", &clk_pll1), | 136 | INIT_CK(NULL, "pll1", &clk_pll1), |
102 | INIT_CK(NULL, "fclk", &clk_f), | 137 | INIT_CK(NULL, "fclk", &clk_f), |
103 | INIT_CK(NULL, "hclk", &clk_h), | 138 | INIT_CK(NULL, "hclk", &clk_h), |
104 | INIT_CK(NULL, "pclk", &clk_p), | 139 | INIT_CK(NULL, "pclk", &clk_p), |
105 | INIT_CK(NULL, "pll2", &clk_pll2), | 140 | INIT_CK(NULL, "pll2", &clk_pll2), |
106 | INIT_CK(NULL, "usb_host", &clk_usb_host), | 141 | INIT_CK("ep93xx-ohci", NULL, &clk_usb_host), |
107 | INIT_CK(NULL, "m2p0", &clk_m2p0), | 142 | INIT_CK(NULL, "m2p0", &clk_m2p0), |
108 | INIT_CK(NULL, "m2p1", &clk_m2p1), | 143 | INIT_CK(NULL, "m2p1", &clk_m2p1), |
109 | INIT_CK(NULL, "m2p2", &clk_m2p2), | 144 | INIT_CK(NULL, "m2p2", &clk_m2p2), |
@@ -125,6 +160,8 @@ int clk_enable(struct clk *clk) | |||
125 | u32 value; | 160 | u32 value; |
126 | 161 | ||
127 | value = __raw_readl(clk->enable_reg); | 162 | value = __raw_readl(clk->enable_reg); |
163 | if (clk->sw_locked) | ||
164 | __raw_writel(0xaa, EP93XX_SYSCON_SWLOCK); | ||
128 | __raw_writel(value | clk->enable_mask, clk->enable_reg); | 165 | __raw_writel(value | clk->enable_mask, clk->enable_reg); |
129 | } | 166 | } |
130 | 167 | ||
@@ -138,13 +175,29 @@ void clk_disable(struct clk *clk) | |||
138 | u32 value; | 175 | u32 value; |
139 | 176 | ||
140 | value = __raw_readl(clk->enable_reg); | 177 | value = __raw_readl(clk->enable_reg); |
178 | if (clk->sw_locked) | ||
179 | __raw_writel(0xaa, EP93XX_SYSCON_SWLOCK); | ||
141 | __raw_writel(value & ~clk->enable_mask, clk->enable_reg); | 180 | __raw_writel(value & ~clk->enable_mask, clk->enable_reg); |
142 | } | 181 | } |
143 | } | 182 | } |
144 | EXPORT_SYMBOL(clk_disable); | 183 | EXPORT_SYMBOL(clk_disable); |
145 | 184 | ||
185 | static unsigned long get_uart_rate(struct clk *clk) | ||
186 | { | ||
187 | u32 value; | ||
188 | |||
189 | value = __raw_readl(EP93XX_SYSCON_PWRCNT); | ||
190 | if (value & EP93XX_SYSCON_PWRCNT_UARTBAUD) | ||
191 | return EP93XX_EXT_CLK_RATE; | ||
192 | else | ||
193 | return EP93XX_EXT_CLK_RATE / 2; | ||
194 | } | ||
195 | |||
146 | unsigned long clk_get_rate(struct clk *clk) | 196 | unsigned long clk_get_rate(struct clk *clk) |
147 | { | 197 | { |
198 | if (clk->get_rate) | ||
199 | return clk->get_rate(clk); | ||
200 | |||
148 | return clk->rate; | 201 | return clk->rate; |
149 | } | 202 | } |
150 | EXPORT_SYMBOL(clk_get_rate); | 203 | EXPORT_SYMBOL(clk_get_rate); |
@@ -162,7 +215,7 @@ static unsigned long calc_pll_rate(u32 config_word) | |||
162 | unsigned long long rate; | 215 | unsigned long long rate; |
163 | int i; | 216 | int i; |
164 | 217 | ||
165 | rate = 14745600; | 218 | rate = EP93XX_EXT_CLK_RATE; |
166 | rate *= ((config_word >> 11) & 0x1f) + 1; /* X1FBD */ | 219 | rate *= ((config_word >> 11) & 0x1f) + 1; /* X1FBD */ |
167 | rate *= ((config_word >> 5) & 0x3f) + 1; /* X2FBD */ | 220 | rate *= ((config_word >> 5) & 0x3f) + 1; /* X2FBD */ |
168 | do_div(rate, (config_word & 0x1f) + 1); /* X2IPD */ | 221 | do_div(rate, (config_word & 0x1f) + 1); /* X2IPD */ |
@@ -195,7 +248,7 @@ static int __init ep93xx_clock_init(void) | |||
195 | 248 | ||
196 | value = __raw_readl(EP93XX_SYSCON_CLOCK_SET1); | 249 | value = __raw_readl(EP93XX_SYSCON_CLOCK_SET1); |
197 | if (!(value & 0x00800000)) { /* PLL1 bypassed? */ | 250 | if (!(value & 0x00800000)) { /* PLL1 bypassed? */ |
198 | clk_pll1.rate = 14745600; | 251 | clk_pll1.rate = EP93XX_EXT_CLK_RATE; |
199 | } else { | 252 | } else { |
200 | clk_pll1.rate = calc_pll_rate(value); | 253 | clk_pll1.rate = calc_pll_rate(value); |
201 | } | 254 | } |
@@ -206,7 +259,7 @@ static int __init ep93xx_clock_init(void) | |||
206 | 259 | ||
207 | value = __raw_readl(EP93XX_SYSCON_CLOCK_SET2); | 260 | value = __raw_readl(EP93XX_SYSCON_CLOCK_SET2); |
208 | if (!(value & 0x00080000)) { /* PLL2 bypassed? */ | 261 | if (!(value & 0x00080000)) { /* PLL2 bypassed? */ |
209 | clk_pll2.rate = 14745600; | 262 | clk_pll2.rate = EP93XX_EXT_CLK_RATE; |
210 | } else if (value & 0x00040000) { /* PLL2 enabled? */ | 263 | } else if (value & 0x00040000) { /* PLL2 enabled? */ |
211 | clk_pll2.rate = calc_pll_rate(value); | 264 | clk_pll2.rate = calc_pll_rate(value); |
212 | } else { | 265 | } else { |