]>
Commit | Line | Data |
---|---|---|
f87fa62a CN |
1 | /* |
2 | * clock.c | |
3 | * | |
4 | * clocks for AM33XX based boards | |
5 | * | |
6 | * Copyright (C) 2011, Texas Instruments, Incorporated - http://www.ti.com/ | |
7 | * | |
8 | * This program is free software; you can redistribute it and/or | |
9 | * modify it under the terms of the GNU General Public License as | |
10 | * published by the Free Software Foundation; either version 2 of | |
11 | * the License, or (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 | ||
19 | #include <common.h> | |
20 | #include <asm/arch/cpu.h> | |
21 | #include <asm/arch/clock.h> | |
22 | #include <asm/arch/hardware.h> | |
23 | #include <asm/io.h> | |
24 | ||
25 | #define PRCM_MOD_EN 0x2 | |
26 | #define PRCM_FORCE_WAKEUP 0x2 | |
e79cd8eb | 27 | #define PRCM_FUNCTL 0x0 |
f87fa62a CN |
28 | |
29 | #define PRCM_EMIF_CLK_ACTIVITY BIT(2) | |
30 | #define PRCM_L3_GCLK_ACTIVITY BIT(4) | |
31 | ||
32 | #define PLL_BYPASS_MODE 0x4 | |
33 | #define ST_MN_BYPASS 0x00000100 | |
34 | #define ST_DPLL_CLK 0x00000001 | |
35 | #define CLK_SEL_MASK 0x7ffff | |
36 | #define CLK_DIV_MASK 0x1f | |
37 | #define CLK_DIV2_MASK 0x7f | |
38 | #define CLK_SEL_SHIFT 0x8 | |
39 | #define CLK_MODE_SEL 0x7 | |
40 | #define CLK_MODE_MASK 0xfffffff8 | |
41 | #define CLK_DIV_SEL 0xFFFFFFE0 | |
e79cd8eb | 42 | #define CPGMAC0_IDLE 0x30000 |
7df5cf35 | 43 | #define DPLL_CLKDCOLDO_GATE_CTRL 0x300 |
f87fa62a CN |
44 | |
45 | const struct cm_perpll *cmper = (struct cm_perpll *)CM_PER; | |
46 | const struct cm_wkuppll *cmwkup = (struct cm_wkuppll *)CM_WKUP; | |
47 | const struct cm_dpll *cmdpll = (struct cm_dpll *)CM_DPLL; | |
000820b5 | 48 | const struct cm_rtc *cmrtc = (struct cm_rtc *)CM_RTC; |
f87fa62a CN |
49 | |
50 | static void enable_interface_clocks(void) | |
51 | { | |
52 | /* Enable all the Interconnect Modules */ | |
53 | writel(PRCM_MOD_EN, &cmper->l3clkctrl); | |
54 | while (readl(&cmper->l3clkctrl) != PRCM_MOD_EN) | |
55 | ; | |
56 | ||
57 | writel(PRCM_MOD_EN, &cmper->l4lsclkctrl); | |
58 | while (readl(&cmper->l4lsclkctrl) != PRCM_MOD_EN) | |
59 | ; | |
60 | ||
61 | writel(PRCM_MOD_EN, &cmper->l4fwclkctrl); | |
62 | while (readl(&cmper->l4fwclkctrl) != PRCM_MOD_EN) | |
63 | ; | |
64 | ||
65 | writel(PRCM_MOD_EN, &cmwkup->wkl4wkclkctrl); | |
66 | while (readl(&cmwkup->wkl4wkclkctrl) != PRCM_MOD_EN) | |
67 | ; | |
68 | ||
69 | writel(PRCM_MOD_EN, &cmper->l3instrclkctrl); | |
70 | while (readl(&cmper->l3instrclkctrl) != PRCM_MOD_EN) | |
71 | ; | |
72 | ||
73 | writel(PRCM_MOD_EN, &cmper->l4hsclkctrl); | |
74 | while (readl(&cmper->l4hsclkctrl) != PRCM_MOD_EN) | |
a438c756 TR |
75 | ; |
76 | ||
77 | writel(PRCM_MOD_EN, &cmwkup->wkgpio0clkctrl); | |
78 | while (readl(&cmwkup->wkgpio0clkctrl) != PRCM_MOD_EN) | |
f87fa62a CN |
79 | ; |
80 | } | |
81 | ||
82 | /* | |
83 | * Force power domain wake up transition | |
84 | * Ensure that the corresponding interface clock is active before | |
85 | * using the peripheral | |
86 | */ | |
87 | static void power_domain_wkup_transition(void) | |
88 | { | |
89 | writel(PRCM_FORCE_WAKEUP, &cmper->l3clkstctrl); | |
90 | writel(PRCM_FORCE_WAKEUP, &cmper->l4lsclkstctrl); | |
91 | writel(PRCM_FORCE_WAKEUP, &cmwkup->wkclkstctrl); | |
92 | writel(PRCM_FORCE_WAKEUP, &cmper->l4fwclkstctrl); | |
93 | writel(PRCM_FORCE_WAKEUP, &cmper->l3sclkstctrl); | |
94 | } | |
95 | ||
96 | /* | |
97 | * Enable the peripheral clock for required peripherals | |
98 | */ | |
99 | static void enable_per_clocks(void) | |
100 | { | |
101 | /* Enable the control module though RBL would have done it*/ | |
102 | writel(PRCM_MOD_EN, &cmwkup->wkctrlclkctrl); | |
103 | while (readl(&cmwkup->wkctrlclkctrl) != PRCM_MOD_EN) | |
104 | ; | |
105 | ||
106 | /* Enable the module clock */ | |
107 | writel(PRCM_MOD_EN, &cmper->timer2clkctrl); | |
108 | while (readl(&cmper->timer2clkctrl) != PRCM_MOD_EN) | |
109 | ; | |
110 | ||
fb072a3e CN |
111 | /* Select the Master osc 24 MHZ as Timer2 clock source */ |
112 | writel(0x1, &cmdpll->clktimer2clk); | |
113 | ||
f87fa62a CN |
114 | /* UART0 */ |
115 | writel(PRCM_MOD_EN, &cmwkup->wkup_uart0ctrl); | |
116 | while (readl(&cmwkup->wkup_uart0ctrl) != PRCM_MOD_EN) | |
117 | ; | |
876bdd6d | 118 | |
25164218 AB |
119 | /* UART1 */ |
120 | #ifdef CONFIG_SERIAL2 | |
121 | writel(PRCM_MOD_EN, &cmper->uart1clkctrl); | |
122 | while (readl(&cmper->uart1clkctrl) != PRCM_MOD_EN) | |
123 | ; | |
124 | #endif /* CONFIG_SERIAL2 */ | |
125 | ||
126 | /* UART2 */ | |
127 | #ifdef CONFIG_SERIAL3 | |
128 | writel(PRCM_MOD_EN, &cmper->uart2clkctrl); | |
129 | while (readl(&cmper->uart2clkctrl) != PRCM_MOD_EN) | |
130 | ; | |
131 | #endif /* CONFIG_SERIAL3 */ | |
132 | ||
133 | /* UART3 */ | |
134 | #ifdef CONFIG_SERIAL4 | |
135 | writel(PRCM_MOD_EN, &cmper->uart3clkctrl); | |
136 | while (readl(&cmper->uart3clkctrl) != PRCM_MOD_EN) | |
137 | ; | |
138 | #endif /* CONFIG_SERIAL4 */ | |
139 | ||
140 | /* UART4 */ | |
141 | #ifdef CONFIG_SERIAL5 | |
142 | writel(PRCM_MOD_EN, &cmper->uart4clkctrl); | |
143 | while (readl(&cmper->uart4clkctrl) != PRCM_MOD_EN) | |
144 | ; | |
145 | #endif /* CONFIG_SERIAL5 */ | |
146 | ||
147 | /* UART5 */ | |
148 | #ifdef CONFIG_SERIAL6 | |
149 | writel(PRCM_MOD_EN, &cmper->uart5clkctrl); | |
150 | while (readl(&cmper->uart5clkctrl) != PRCM_MOD_EN) | |
151 | ; | |
152 | #endif /* CONFIG_SERIAL6 */ | |
153 | ||
8eb16b7f IY |
154 | /* GPMC */ |
155 | writel(PRCM_MOD_EN, &cmper->gpmcclkctrl); | |
156 | while (readl(&cmper->gpmcclkctrl) != PRCM_MOD_EN) | |
157 | ; | |
158 | ||
04c37578 MA |
159 | /* ELM */ |
160 | writel(PRCM_MOD_EN, &cmper->elmclkctrl); | |
161 | while (readl(&cmper->elmclkctrl) != PRCM_MOD_EN) | |
162 | ; | |
163 | ||
876bdd6d CN |
164 | /* MMC0*/ |
165 | writel(PRCM_MOD_EN, &cmper->mmc0clkctrl); | |
166 | while (readl(&cmper->mmc0clkctrl) != PRCM_MOD_EN) | |
167 | ; | |
b4116ede PR |
168 | |
169 | /* i2c0 */ | |
170 | writel(PRCM_MOD_EN, &cmwkup->wkup_i2c0ctrl); | |
171 | while (readl(&cmwkup->wkup_i2c0ctrl) != PRCM_MOD_EN) | |
172 | ; | |
3b97152b SS |
173 | |
174 | /* gpio1 module */ | |
175 | writel(PRCM_MOD_EN, &cmper->gpio1clkctrl); | |
176 | while (readl(&cmper->gpio1clkctrl) != PRCM_MOD_EN) | |
177 | ; | |
178 | ||
179 | /* gpio2 module */ | |
180 | writel(PRCM_MOD_EN, &cmper->gpio2clkctrl); | |
181 | while (readl(&cmper->gpio2clkctrl) != PRCM_MOD_EN) | |
182 | ; | |
183 | ||
184 | /* gpio3 module */ | |
185 | writel(PRCM_MOD_EN, &cmper->gpio3clkctrl); | |
186 | while (readl(&cmper->gpio3clkctrl) != PRCM_MOD_EN) | |
187 | ; | |
d3decdeb SS |
188 | |
189 | /* i2c1 */ | |
190 | writel(PRCM_MOD_EN, &cmper->i2c1clkctrl); | |
191 | while (readl(&cmper->i2c1clkctrl) != PRCM_MOD_EN) | |
192 | ; | |
e79cd8eb CN |
193 | |
194 | /* Ethernet */ | |
195 | writel(PRCM_MOD_EN, &cmper->cpgmac0clkctrl); | |
196 | while ((readl(&cmper->cpgmac0clkctrl) & CPGMAC0_IDLE) != PRCM_FUNCTL) | |
197 | ; | |
4c0620bf TR |
198 | |
199 | /* spi0 */ | |
200 | writel(PRCM_MOD_EN, &cmper->spi0clkctrl); | |
201 | while (readl(&cmper->spi0clkctrl) != PRCM_MOD_EN) | |
202 | ; | |
000820b5 VH |
203 | |
204 | /* RTC */ | |
205 | writel(PRCM_MOD_EN, &cmrtc->rtcclkctrl); | |
206 | while (readl(&cmrtc->rtcclkctrl) != PRCM_MOD_EN) | |
207 | ; | |
7df5cf35 IY |
208 | |
209 | /* MUSB */ | |
210 | writel(PRCM_MOD_EN, &cmper->usb0clkctrl); | |
211 | while (readl(&cmper->usb0clkctrl) != PRCM_MOD_EN) | |
212 | ; | |
f87fa62a CN |
213 | } |
214 | ||
215 | static void mpu_pll_config(void) | |
216 | { | |
217 | u32 clkmode, clksel, div_m2; | |
218 | ||
219 | clkmode = readl(&cmwkup->clkmoddpllmpu); | |
220 | clksel = readl(&cmwkup->clkseldpllmpu); | |
221 | div_m2 = readl(&cmwkup->divm2dpllmpu); | |
222 | ||
223 | /* Set the PLL to bypass Mode */ | |
224 | writel(PLL_BYPASS_MODE, &cmwkup->clkmoddpllmpu); | |
225 | while (readl(&cmwkup->idlestdpllmpu) != ST_MN_BYPASS) | |
226 | ; | |
227 | ||
228 | clksel = clksel & (~CLK_SEL_MASK); | |
229 | clksel = clksel | ((MPUPLL_M << CLK_SEL_SHIFT) | MPUPLL_N); | |
230 | writel(clksel, &cmwkup->clkseldpllmpu); | |
231 | ||
232 | div_m2 = div_m2 & ~CLK_DIV_MASK; | |
233 | div_m2 = div_m2 | MPUPLL_M2; | |
234 | writel(div_m2, &cmwkup->divm2dpllmpu); | |
235 | ||
236 | clkmode = clkmode | CLK_MODE_SEL; | |
237 | writel(clkmode, &cmwkup->clkmoddpllmpu); | |
238 | ||
239 | while (readl(&cmwkup->idlestdpllmpu) != ST_DPLL_CLK) | |
240 | ; | |
241 | } | |
242 | ||
243 | static void core_pll_config(void) | |
244 | { | |
245 | u32 clkmode, clksel, div_m4, div_m5, div_m6; | |
246 | ||
247 | clkmode = readl(&cmwkup->clkmoddpllcore); | |
248 | clksel = readl(&cmwkup->clkseldpllcore); | |
249 | div_m4 = readl(&cmwkup->divm4dpllcore); | |
250 | div_m5 = readl(&cmwkup->divm5dpllcore); | |
251 | div_m6 = readl(&cmwkup->divm6dpllcore); | |
252 | ||
253 | /* Set the PLL to bypass Mode */ | |
254 | writel(PLL_BYPASS_MODE, &cmwkup->clkmoddpllcore); | |
255 | ||
256 | while (readl(&cmwkup->idlestdpllcore) != ST_MN_BYPASS) | |
257 | ; | |
258 | ||
259 | clksel = clksel & (~CLK_SEL_MASK); | |
260 | clksel = clksel | ((COREPLL_M << CLK_SEL_SHIFT) | COREPLL_N); | |
261 | writel(clksel, &cmwkup->clkseldpllcore); | |
262 | ||
263 | div_m4 = div_m4 & ~CLK_DIV_MASK; | |
264 | div_m4 = div_m4 | COREPLL_M4; | |
265 | writel(div_m4, &cmwkup->divm4dpllcore); | |
266 | ||
267 | div_m5 = div_m5 & ~CLK_DIV_MASK; | |
268 | div_m5 = div_m5 | COREPLL_M5; | |
269 | writel(div_m5, &cmwkup->divm5dpllcore); | |
270 | ||
271 | div_m6 = div_m6 & ~CLK_DIV_MASK; | |
272 | div_m6 = div_m6 | COREPLL_M6; | |
273 | writel(div_m6, &cmwkup->divm6dpllcore); | |
274 | ||
275 | clkmode = clkmode | CLK_MODE_SEL; | |
276 | writel(clkmode, &cmwkup->clkmoddpllcore); | |
277 | ||
278 | while (readl(&cmwkup->idlestdpllcore) != ST_DPLL_CLK) | |
279 | ; | |
280 | } | |
281 | ||
282 | static void per_pll_config(void) | |
283 | { | |
284 | u32 clkmode, clksel, div_m2; | |
285 | ||
286 | clkmode = readl(&cmwkup->clkmoddpllper); | |
287 | clksel = readl(&cmwkup->clkseldpllper); | |
288 | div_m2 = readl(&cmwkup->divm2dpllper); | |
289 | ||
290 | /* Set the PLL to bypass Mode */ | |
291 | writel(PLL_BYPASS_MODE, &cmwkup->clkmoddpllper); | |
292 | ||
293 | while (readl(&cmwkup->idlestdpllper) != ST_MN_BYPASS) | |
294 | ; | |
295 | ||
296 | clksel = clksel & (~CLK_SEL_MASK); | |
297 | clksel = clksel | ((PERPLL_M << CLK_SEL_SHIFT) | PERPLL_N); | |
298 | writel(clksel, &cmwkup->clkseldpllper); | |
299 | ||
300 | div_m2 = div_m2 & ~CLK_DIV2_MASK; | |
301 | div_m2 = div_m2 | PERPLL_M2; | |
302 | writel(div_m2, &cmwkup->divm2dpllper); | |
303 | ||
304 | clkmode = clkmode | CLK_MODE_SEL; | |
305 | writel(clkmode, &cmwkup->clkmoddpllper); | |
306 | ||
307 | while (readl(&cmwkup->idlestdpllper) != ST_DPLL_CLK) | |
308 | ; | |
7df5cf35 IY |
309 | |
310 | writel(DPLL_CLKDCOLDO_GATE_CTRL, &cmwkup->clkdcoldodpllper); | |
f87fa62a CN |
311 | } |
312 | ||
b971dfad | 313 | void ddr_pll_config(unsigned int ddrpll_m) |
f87fa62a CN |
314 | { |
315 | u32 clkmode, clksel, div_m2; | |
316 | ||
317 | clkmode = readl(&cmwkup->clkmoddpllddr); | |
318 | clksel = readl(&cmwkup->clkseldpllddr); | |
319 | div_m2 = readl(&cmwkup->divm2dpllddr); | |
320 | ||
321 | /* Set the PLL to bypass Mode */ | |
322 | clkmode = (clkmode & CLK_MODE_MASK) | PLL_BYPASS_MODE; | |
323 | writel(clkmode, &cmwkup->clkmoddpllddr); | |
324 | ||
325 | /* Wait till bypass mode is enabled */ | |
326 | while ((readl(&cmwkup->idlestdpllddr) & ST_MN_BYPASS) | |
327 | != ST_MN_BYPASS) | |
328 | ; | |
329 | ||
330 | clksel = clksel & (~CLK_SEL_MASK); | |
b971dfad | 331 | clksel = clksel | ((ddrpll_m << CLK_SEL_SHIFT) | DDRPLL_N); |
f87fa62a CN |
332 | writel(clksel, &cmwkup->clkseldpllddr); |
333 | ||
334 | div_m2 = div_m2 & CLK_DIV_SEL; | |
335 | div_m2 = div_m2 | DDRPLL_M2; | |
336 | writel(div_m2, &cmwkup->divm2dpllddr); | |
337 | ||
338 | clkmode = (clkmode & CLK_MODE_MASK) | CLK_MODE_SEL; | |
339 | writel(clkmode, &cmwkup->clkmoddpllddr); | |
340 | ||
341 | /* Wait till dpll is locked */ | |
342 | while ((readl(&cmwkup->idlestdpllddr) & ST_DPLL_CLK) != ST_DPLL_CLK) | |
343 | ; | |
344 | } | |
345 | ||
346 | void enable_emif_clocks(void) | |
347 | { | |
348 | /* Enable the EMIF_FW Functional clock */ | |
349 | writel(PRCM_MOD_EN, &cmper->emiffwclkctrl); | |
350 | /* Enable EMIF0 Clock */ | |
351 | writel(PRCM_MOD_EN, &cmper->emifclkctrl); | |
f87fa62a CN |
352 | /* Poll if module is functional */ |
353 | while ((readl(&cmper->emifclkctrl)) != PRCM_MOD_EN) | |
354 | ; | |
355 | } | |
356 | ||
357 | /* | |
358 | * Configure the PLL/PRCM for necessary peripherals | |
359 | */ | |
360 | void pll_init() | |
361 | { | |
362 | mpu_pll_config(); | |
363 | core_pll_config(); | |
364 | per_pll_config(); | |
f87fa62a CN |
365 | |
366 | /* Enable the required interconnect clocks */ | |
367 | enable_interface_clocks(); | |
368 | ||
369 | /* Power domain wake up transition */ | |
370 | power_domain_wkup_transition(); | |
371 | ||
372 | /* Enable the required peripherals */ | |
373 | enable_per_clocks(); | |
374 | } |