]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - arch/arm/cpu/armv7/am33xx/clock.c
TX6 Release 2013-04-22
[karo-tx-uboot.git] / arch / arm / cpu / armv7 / am33xx / clock.c
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
27 #define PRCM_FUNCTL             0x0
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_MASK           0x7
40 #define CLK_MODE_SEL            0x7
41 #define DPLL_CLKDCOLDO_GATE_CTRL 0x300
42
43
44 const struct cm_perpll *cmper = (struct cm_perpll *)CM_PER;
45 const struct cm_wkuppll *cmwkup = (struct cm_wkuppll *)CM_WKUP;
46 const struct cm_dpll *cmdpll = (struct cm_dpll *)CM_DPLL;
47 const struct cm_rtc *cmrtc = (struct cm_rtc *)CM_RTC;
48
49 #ifdef CONFIG_SPL_BUILD
50 #define enable_clk(reg, val) __enable_clk(#reg, &reg, val)
51
52 static void __enable_clk(const char *name, const void *reg, u32 mask)
53 {
54         unsigned long timeout = 10000000;
55
56         writel(mask, reg);
57         while (readl(reg) != mask)
58                 /* poor man's timeout, since timers not initialized */
59                 if (timeout-- == 0)
60                         /* no error message, since console not yet available */
61                         break;
62 }
63
64 static void enable_interface_clocks(void)
65 {
66         /* Enable all the Interconnect Modules */
67         enable_clk(cmper->l3clkctrl, PRCM_MOD_EN);
68         enable_clk(cmper->l4lsclkctrl, PRCM_MOD_EN);
69         enable_clk(cmper->l4fwclkctrl, PRCM_MOD_EN);
70         enable_clk(cmwkup->wkl4wkclkctrl, PRCM_MOD_EN);
71         enable_clk(cmper->l3instrclkctrl, PRCM_MOD_EN);
72         enable_clk(cmper->l4hsclkctrl, PRCM_MOD_EN);
73 #ifdef CONFIG_HW_WATCHDOG
74         enable_clk(cmwkup->wdtimer1ctrl, PRCM_MOD_EN);
75 #endif
76         /* GPIO0 */
77         enable_clk(cmwkup->wkgpio0clkctrl, PRCM_MOD_EN);
78 }
79
80 /*
81  * Force power domain wake up transition
82  * Ensure that the corresponding interface clock is active before
83  * using the peripheral
84  */
85 static void power_domain_wkup_transition(void)
86 {
87         writel(PRCM_FORCE_WAKEUP, &cmper->l3clkstctrl);
88         writel(PRCM_FORCE_WAKEUP, &cmper->l4lsclkstctrl);
89         writel(PRCM_FORCE_WAKEUP, &cmwkup->wkclkstctrl);
90         writel(PRCM_FORCE_WAKEUP, &cmper->l4fwclkstctrl);
91         writel(PRCM_FORCE_WAKEUP, &cmper->l3sclkstctrl);
92 }
93
94 /*
95  * Enable the peripheral clock for required peripherals
96  */
97 static void enable_per_clocks(void)
98 {
99         /* Enable the control module though RBL would have done it*/
100         enable_clk(cmwkup->wkctrlclkctrl, PRCM_MOD_EN);
101         /* Enable the timer2 clock */
102         enable_clk(cmper->timer2clkctrl, PRCM_MOD_EN);
103         /* Select the Master osc 24 MHZ as Timer2 clock source */
104         writel(0x1, &cmdpll->clktimer2clk);
105
106 #ifdef CONFIG_SYS_NS16550_COM1
107         /* UART0 */
108         enable_clk(cmwkup->wkup_uart0ctrl, PRCM_MOD_EN);
109 #endif
110 #ifdef CONFIG_SYS_NS16550_COM2
111         enable_clk(cmper->uart1clkctrl, PRCM_MOD_EN);
112 #endif
113 #ifdef CONFIG_SYS_NS16550_COM3
114         enable_clk(cmper->uart2clkctrl, PRCM_MOD_EN);
115 #endif
116 #ifdef CONFIG_SYS_NS16550_COM4
117         enable_clk(cmper->uart3clkctrl, PRCM_MOD_EN);
118 #endif
119 #ifdef CONFIG_SYS_NS16550_COM5
120         enable_clk(cmper->uart4clkctrl, PRCM_MOD_EN);
121 #endif
122 #ifdef CONFIG_SYS_NS16550_COM6
123         enable_clk(cmper->uart5clkctrl, PRCM_MOD_EN);
124 #endif
125         /* GPMC */
126         enable_clk(cmper->gpmcclkctrl, PRCM_MOD_EN);
127
128         /* ELM */
129         enable_clk(cmper->elmclkctrl, PRCM_MOD_EN);
130
131         /* Ethernet */
132         enable_clk(cmper->cpswclkstctrl, PRCM_MOD_EN);
133         enable_clk(cmper->cpgmac0clkctrl, PRCM_MOD_EN);
134
135         /* MMC */
136 #ifndef CONFIG_OMAP_MMC_DEV_0
137         enable_clk(cmper->mmc0clkctrl, PRCM_MOD_EN);
138 #endif
139 #ifdef CONFIG_OMAP_MMC_DEV_1
140         enable_clk(cmper->mmc1clkctrl, PRCM_MOD_EN);
141 #endif
142         /* LCD */
143         enable_clk(cmper->lcdclkctrl, PRCM_MOD_EN);
144
145         /* i2c0 */
146         enable_clk(cmwkup->wkup_i2c0ctrl, PRCM_MOD_EN);
147
148         /* GPIO1-3 */
149         enable_clk(cmper->gpio1clkctrl, PRCM_MOD_EN);
150         enable_clk(cmper->gpio2clkctrl, PRCM_MOD_EN);
151         enable_clk(cmper->gpio3clkctrl, PRCM_MOD_EN);
152
153         /* i2c1 */
154         enable_clk(cmper->i2c1clkctrl, PRCM_MOD_EN);
155
156         /* spi0 */
157         enable_clk(cmper->spi0clkctrl, PRCM_MOD_EN);
158
159         /* rtc */
160         enable_clk(cmrtc->rtcclkctrl, PRCM_MOD_EN);
161
162         /* usb0 */
163         enable_clk(cmper->usb0clkctrl, PRCM_MOD_EN);
164 }
165
166 static void mpu_pll_config(void)
167 {
168         u32 clkmode, clksel, div_m2;
169
170         clkmode = readl(&cmwkup->clkmoddpllmpu);
171         clksel = readl(&cmwkup->clkseldpllmpu);
172         div_m2 = readl(&cmwkup->divm2dpllmpu);
173
174         /* Set the PLL to bypass Mode */
175         writel(PLL_BYPASS_MODE, &cmwkup->clkmoddpllmpu);
176         while (readl(&cmwkup->idlestdpllmpu) != ST_MN_BYPASS)
177                 ;
178
179         clksel &= ~CLK_SEL_MASK;
180         clksel |= (MPUPLL_M << CLK_SEL_SHIFT) | MPUPLL_N;
181         writel(clksel, &cmwkup->clkseldpllmpu);
182
183         div_m2 &= ~CLK_DIV_MASK;
184         div_m2 |= MPUPLL_M2;
185         writel(div_m2, &cmwkup->divm2dpllmpu);
186
187         clkmode &= ~CLK_MODE_MASK;
188         clkmode |= CLK_MODE_SEL;
189         writel(clkmode, &cmwkup->clkmoddpllmpu);
190
191         while (readl(&cmwkup->idlestdpllmpu) != ST_DPLL_CLK)
192                 ;
193 }
194
195 static void core_pll_config(void)
196 {
197         u32 clkmode, clksel, div_m4, div_m5, div_m6;
198
199         clkmode = readl(&cmwkup->clkmoddpllcore);
200         clksel = readl(&cmwkup->clkseldpllcore);
201         div_m4 = readl(&cmwkup->divm4dpllcore);
202         div_m5 = readl(&cmwkup->divm5dpllcore);
203         div_m6 = readl(&cmwkup->divm6dpllcore);
204
205         /* Set the PLL to bypass Mode */
206         writel(PLL_BYPASS_MODE, &cmwkup->clkmoddpllcore);
207
208         while (readl(&cmwkup->idlestdpllcore) != ST_MN_BYPASS)
209                 ;
210
211         clksel &= ~CLK_SEL_MASK;
212         clksel |= ((COREPLL_M << CLK_SEL_SHIFT) | COREPLL_N);
213         writel(clksel, &cmwkup->clkseldpllcore);
214
215         div_m4 &= ~CLK_DIV_MASK;
216         div_m4 |= COREPLL_M4;
217         writel(div_m4, &cmwkup->divm4dpllcore);
218
219         div_m5 &= ~CLK_DIV_MASK;
220         div_m5 |= COREPLL_M5;
221         writel(div_m5, &cmwkup->divm5dpllcore);
222
223         div_m6 &= ~CLK_DIV_MASK;
224         div_m6 |= COREPLL_M6;
225         writel(div_m6, &cmwkup->divm6dpllcore);
226
227         clkmode &= ~CLK_MODE_MASK;
228         clkmode |= CLK_MODE_SEL;
229         writel(clkmode, &cmwkup->clkmoddpllcore);
230
231         while (readl(&cmwkup->idlestdpllcore) != ST_DPLL_CLK)
232                 ;
233 }
234
235 static void per_pll_config(void)
236 {
237         u32 clkmode, clksel, div_m2;
238
239         clkmode = readl(&cmwkup->clkmoddpllper);
240         clksel = readl(&cmwkup->clkseldpllper);
241         div_m2 = readl(&cmwkup->divm2dpllper);
242
243         /* Set the PLL to bypass Mode */
244         writel(PLL_BYPASS_MODE, &cmwkup->clkmoddpllper);
245
246         while (readl(&cmwkup->idlestdpllper) != ST_MN_BYPASS)
247                 ;
248
249         clksel &= ~CLK_SEL_MASK;
250         clksel |= (PERPLL_M << CLK_SEL_SHIFT) | PERPLL_N;
251         writel(clksel, &cmwkup->clkseldpllper);
252
253         div_m2 &= ~CLK_DIV2_MASK;
254         div_m2 |= PERPLL_M2;
255         writel(div_m2, &cmwkup->divm2dpllper);
256
257         clkmode &= ~CLK_MODE_MASK;
258         clkmode |= CLK_MODE_SEL;
259         writel(clkmode, &cmwkup->clkmoddpllper);
260
261         while (readl(&cmwkup->idlestdpllper) != ST_DPLL_CLK)
262                 ;
263
264         writel(DPLL_CLKDCOLDO_GATE_CTRL, &cmwkup->clkdcoldodpllper);
265 }
266
267 static void disp_pll_config(void)
268 {
269         u32 clkmode, clksel, div_m2;
270
271         clkmode = readl(&cmwkup->clkmoddplldisp);
272         clksel = readl(&cmwkup->clkseldplldisp);
273         div_m2 = readl(&cmwkup->divm2dplldisp);
274
275         /* Set the PLL to bypass Mode */
276         writel(PLL_BYPASS_MODE, &cmwkup->clkmoddplldisp);
277
278         while (!(readl(&cmwkup->idlestdplldisp) & ST_MN_BYPASS))
279                 ;
280
281         clksel &= ~CLK_SEL_MASK;
282         clksel |= (DISPPLL_M << CLK_SEL_SHIFT) | DISPPLL_N;
283         writel(clksel, &cmwkup->clkseldplldisp);
284
285         div_m2 &= ~CLK_DIV2_MASK;
286         div_m2 |= DISPPLL_M2;
287         writel(div_m2, &cmwkup->divm2dplldisp);
288
289         clkmode &= ~CLK_MODE_MASK;
290         clkmode |= CLK_MODE_SEL;
291         writel(clkmode, &cmwkup->clkmoddplldisp);
292
293         while (!(readl(&cmwkup->idlestdplldisp) & ST_DPLL_CLK))
294                 ;
295 }
296
297 void ddr_pll_config(unsigned int ddrpll_m)
298 {
299         u32 clkmode, clksel, div_m2;
300
301         clkmode = readl(&cmwkup->clkmoddpllddr);
302         clksel = readl(&cmwkup->clkseldpllddr);
303         div_m2 = readl(&cmwkup->divm2dpllddr);
304
305         /* Set the PLL to bypass Mode */
306         clkmode &= ~CLK_MODE_MASK;
307         clkmode |= PLL_BYPASS_MODE;
308         writel(clkmode, &cmwkup->clkmoddpllddr);
309
310         /* Wait till bypass mode is enabled */
311         while (!(readl(&cmwkup->idlestdpllddr) & ST_MN_BYPASS))
312                 ;
313
314         clksel &= ~CLK_SEL_MASK;
315         clksel |= (ddrpll_m << CLK_SEL_SHIFT) | DDRPLL_N;
316         writel(clksel, &cmwkup->clkseldpllddr);
317
318         div_m2 &= ~CLK_DIV_MASK;
319         div_m2 |= DDRPLL_M2;
320         writel(div_m2, &cmwkup->divm2dpllddr);
321
322         clkmode &= ~CLK_MODE_MASK;
323         clkmode |= CLK_MODE_SEL;
324         writel(clkmode, &cmwkup->clkmoddpllddr);
325
326         /* Wait till dpll is locked */
327         while ((readl(&cmwkup->idlestdpllddr) & ST_DPLL_CLK) != ST_DPLL_CLK)
328                 ;
329 }
330
331 void enable_emif_clocks(void)
332 {
333         /* Enable the  EMIF_FW Functional clock */
334         writel(PRCM_MOD_EN, &cmper->emiffwclkctrl);
335         /* Enable EMIF0 Clock */
336         writel(PRCM_MOD_EN, &cmper->emifclkctrl);
337         /* Poll if module is functional */
338         while ((readl(&cmper->emifclkctrl)) != PRCM_MOD_EN)
339                 ;
340 }
341
342 /*
343  * Configure the PLL/PRCM for necessary peripherals
344  */
345 void pll_init()
346 {
347         mpu_pll_config();
348         core_pll_config();
349         per_pll_config();
350         disp_pll_config();
351
352         /* Enable the required interconnect clocks */
353         enable_interface_clocks();
354
355         /* Power domain wake up transition */
356         power_domain_wkup_transition();
357
358         /* Enable the required peripherals */
359         enable_per_clocks();
360 }
361 #endif
362
363 #define M(mn) (((mn) & CLK_SEL_MASK) >> CLK_SEL_SHIFT)
364 #define N(mn) ((mn) & CLK_DIV2_MASK)
365
366 unsigned long __clk_get_rate(u32 m_n, u32 div_m2)
367 {
368         unsigned long rate;
369
370         div_m2 &= CLK_DIV_MASK;
371         debug("M=%u N=%u M2=%u\n", M(m_n), N(m_n), div_m2);
372         rate = V_OSCK / 1000 * M(m_n) / (N(m_n) + 1) / div_m2;
373         debug("CLK = %lu.%03luMHz\n", rate / 1000, rate % 1000);
374         return rate * 1000;
375 }
376
377 unsigned long lcdc_clk_rate(void)
378 {
379         return clk_get_rate(cmwkup, disp);
380 }