7070e7d37cffb8304b252c7b6d44c34879b44149
[oweals/u-boot.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_SEL            0x7
39 #define CLK_MODE_MASK           0xfffffff8
40 #define CLK_DIV_SEL             0xFFFFFFE0
41
42
43 const struct cm_perpll *cmper = (struct cm_perpll *)CM_PER;
44 const struct cm_wkuppll *cmwkup = (struct cm_wkuppll *)CM_WKUP;
45 const struct cm_dpll *cmdpll = (struct cm_dpll *)CM_DPLL;
46
47 static void enable_interface_clocks(void)
48 {
49         /* Enable all the Interconnect Modules */
50         writel(PRCM_MOD_EN, &cmper->l3clkctrl);
51         while (readl(&cmper->l3clkctrl) != PRCM_MOD_EN)
52                 ;
53
54         writel(PRCM_MOD_EN, &cmper->l4lsclkctrl);
55         while (readl(&cmper->l4lsclkctrl) != PRCM_MOD_EN)
56                 ;
57
58         writel(PRCM_MOD_EN, &cmper->l4fwclkctrl);
59         while (readl(&cmper->l4fwclkctrl) != PRCM_MOD_EN)
60                 ;
61
62         writel(PRCM_MOD_EN, &cmwkup->wkl4wkclkctrl);
63         while (readl(&cmwkup->wkl4wkclkctrl) != PRCM_MOD_EN)
64                 ;
65
66         writel(PRCM_MOD_EN, &cmper->l3instrclkctrl);
67         while (readl(&cmper->l3instrclkctrl) != PRCM_MOD_EN)
68                 ;
69
70         writel(PRCM_MOD_EN, &cmper->l4hsclkctrl);
71         while (readl(&cmper->l4hsclkctrl) != PRCM_MOD_EN)
72                 ;
73 }
74
75 /*
76  * Force power domain wake up transition
77  * Ensure that the corresponding interface clock is active before
78  * using the peripheral
79  */
80 static void power_domain_wkup_transition(void)
81 {
82         writel(PRCM_FORCE_WAKEUP, &cmper->l3clkstctrl);
83         writel(PRCM_FORCE_WAKEUP, &cmper->l4lsclkstctrl);
84         writel(PRCM_FORCE_WAKEUP, &cmwkup->wkclkstctrl);
85         writel(PRCM_FORCE_WAKEUP, &cmper->l4fwclkstctrl);
86         writel(PRCM_FORCE_WAKEUP, &cmper->l3sclkstctrl);
87 }
88
89 /*
90  * Enable the peripheral clock for required peripherals
91  */
92 static void enable_per_clocks(void)
93 {
94         /* Enable the control module though RBL would have done it*/
95         writel(PRCM_MOD_EN, &cmwkup->wkctrlclkctrl);
96         while (readl(&cmwkup->wkctrlclkctrl) != PRCM_MOD_EN)
97                 ;
98
99         /* Enable the module clock */
100         writel(PRCM_MOD_EN, &cmper->timer2clkctrl);
101         while (readl(&cmper->timer2clkctrl) != PRCM_MOD_EN)
102                 ;
103
104         /* Select the Master osc 24 MHZ as Timer2 clock source */
105         writel(0x1, &cmdpll->clktimer2clk);
106
107         /* UART0 */
108         writel(PRCM_MOD_EN, &cmwkup->wkup_uart0ctrl);
109         while (readl(&cmwkup->wkup_uart0ctrl) != PRCM_MOD_EN)
110                 ;
111 }
112
113 static void mpu_pll_config(void)
114 {
115         u32 clkmode, clksel, div_m2;
116
117         clkmode = readl(&cmwkup->clkmoddpllmpu);
118         clksel = readl(&cmwkup->clkseldpllmpu);
119         div_m2 = readl(&cmwkup->divm2dpllmpu);
120
121         /* Set the PLL to bypass Mode */
122         writel(PLL_BYPASS_MODE, &cmwkup->clkmoddpllmpu);
123         while (readl(&cmwkup->idlestdpllmpu) != ST_MN_BYPASS)
124                 ;
125
126         clksel = clksel & (~CLK_SEL_MASK);
127         clksel = clksel | ((MPUPLL_M << CLK_SEL_SHIFT) | MPUPLL_N);
128         writel(clksel, &cmwkup->clkseldpllmpu);
129
130         div_m2 = div_m2 & ~CLK_DIV_MASK;
131         div_m2 = div_m2 | MPUPLL_M2;
132         writel(div_m2, &cmwkup->divm2dpllmpu);
133
134         clkmode = clkmode | CLK_MODE_SEL;
135         writel(clkmode, &cmwkup->clkmoddpllmpu);
136
137         while (readl(&cmwkup->idlestdpllmpu) != ST_DPLL_CLK)
138                 ;
139 }
140
141 static void core_pll_config(void)
142 {
143         u32 clkmode, clksel, div_m4, div_m5, div_m6;
144
145         clkmode = readl(&cmwkup->clkmoddpllcore);
146         clksel = readl(&cmwkup->clkseldpllcore);
147         div_m4 = readl(&cmwkup->divm4dpllcore);
148         div_m5 = readl(&cmwkup->divm5dpllcore);
149         div_m6 = readl(&cmwkup->divm6dpllcore);
150
151         /* Set the PLL to bypass Mode */
152         writel(PLL_BYPASS_MODE, &cmwkup->clkmoddpllcore);
153
154         while (readl(&cmwkup->idlestdpllcore) != ST_MN_BYPASS)
155                 ;
156
157         clksel = clksel & (~CLK_SEL_MASK);
158         clksel = clksel | ((COREPLL_M << CLK_SEL_SHIFT) | COREPLL_N);
159         writel(clksel, &cmwkup->clkseldpllcore);
160
161         div_m4 = div_m4 & ~CLK_DIV_MASK;
162         div_m4 = div_m4 | COREPLL_M4;
163         writel(div_m4, &cmwkup->divm4dpllcore);
164
165         div_m5 = div_m5 & ~CLK_DIV_MASK;
166         div_m5 = div_m5 | COREPLL_M5;
167         writel(div_m5, &cmwkup->divm5dpllcore);
168
169         div_m6 = div_m6 & ~CLK_DIV_MASK;
170         div_m6 = div_m6 | COREPLL_M6;
171         writel(div_m6, &cmwkup->divm6dpllcore);
172
173         clkmode = clkmode | CLK_MODE_SEL;
174         writel(clkmode, &cmwkup->clkmoddpllcore);
175
176         while (readl(&cmwkup->idlestdpllcore) != ST_DPLL_CLK)
177                 ;
178 }
179
180 static void per_pll_config(void)
181 {
182         u32 clkmode, clksel, div_m2;
183
184         clkmode = readl(&cmwkup->clkmoddpllper);
185         clksel = readl(&cmwkup->clkseldpllper);
186         div_m2 = readl(&cmwkup->divm2dpllper);
187
188         /* Set the PLL to bypass Mode */
189         writel(PLL_BYPASS_MODE, &cmwkup->clkmoddpllper);
190
191         while (readl(&cmwkup->idlestdpllper) != ST_MN_BYPASS)
192                 ;
193
194         clksel = clksel & (~CLK_SEL_MASK);
195         clksel = clksel | ((PERPLL_M << CLK_SEL_SHIFT) | PERPLL_N);
196         writel(clksel, &cmwkup->clkseldpllper);
197
198         div_m2 = div_m2 & ~CLK_DIV2_MASK;
199         div_m2 = div_m2 | PERPLL_M2;
200         writel(div_m2, &cmwkup->divm2dpllper);
201
202         clkmode = clkmode | CLK_MODE_SEL;
203         writel(clkmode, &cmwkup->clkmoddpllper);
204
205         while (readl(&cmwkup->idlestdpllper) != ST_DPLL_CLK)
206                 ;
207 }
208
209 static void ddr_pll_config(void)
210 {
211         u32 clkmode, clksel, div_m2;
212
213         clkmode = readl(&cmwkup->clkmoddpllddr);
214         clksel = readl(&cmwkup->clkseldpllddr);
215         div_m2 = readl(&cmwkup->divm2dpllddr);
216
217         /* Set the PLL to bypass Mode */
218         clkmode = (clkmode & CLK_MODE_MASK) | PLL_BYPASS_MODE;
219         writel(clkmode, &cmwkup->clkmoddpllddr);
220
221         /* Wait till bypass mode is enabled */
222         while ((readl(&cmwkup->idlestdpllddr) & ST_MN_BYPASS)
223                                 != ST_MN_BYPASS)
224                 ;
225
226         clksel = clksel & (~CLK_SEL_MASK);
227         clksel = clksel | ((DDRPLL_M << CLK_SEL_SHIFT) | DDRPLL_N);
228         writel(clksel, &cmwkup->clkseldpllddr);
229
230         div_m2 = div_m2 & CLK_DIV_SEL;
231         div_m2 = div_m2 | DDRPLL_M2;
232         writel(div_m2, &cmwkup->divm2dpllddr);
233
234         clkmode = (clkmode & CLK_MODE_MASK) | CLK_MODE_SEL;
235         writel(clkmode, &cmwkup->clkmoddpllddr);
236
237         /* Wait till dpll is locked */
238         while ((readl(&cmwkup->idlestdpllddr) & ST_DPLL_CLK) != ST_DPLL_CLK)
239                 ;
240 }
241
242 void enable_emif_clocks(void)
243 {
244         /* Enable the  EMIF_FW Functional clock */
245         writel(PRCM_MOD_EN, &cmper->emiffwclkctrl);
246         /* Enable EMIF0 Clock */
247         writel(PRCM_MOD_EN, &cmper->emifclkctrl);
248         /* Poll for emif_gclk  & L3_G clock  are active */
249         while ((readl(&cmper->l3clkstctrl) & (PRCM_EMIF_CLK_ACTIVITY |
250                         PRCM_L3_GCLK_ACTIVITY)) != (PRCM_EMIF_CLK_ACTIVITY |
251                         PRCM_L3_GCLK_ACTIVITY))
252                 ;
253         /* Poll if module is functional */
254         while ((readl(&cmper->emifclkctrl)) != PRCM_MOD_EN)
255                 ;
256 }
257
258 /*
259  * Configure the PLL/PRCM for necessary peripherals
260  */
261 void pll_init()
262 {
263         mpu_pll_config();
264         core_pll_config();
265         per_pll_config();
266         ddr_pll_config();
267
268         /* Enable the required interconnect clocks */
269         enable_interface_clocks();
270
271         /* Power domain wake up transition */
272         power_domain_wkup_transition();
273
274         /* Enable the required peripherals */
275         enable_per_clocks();
276 }