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