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