]>
Commit | Line | Data |
---|---|---|
5ed3e865 DB |
1 | /* |
2 | * (C) Copyright 2008 | |
3 | * Texas Instruments, <www.ti.com> | |
4 | * | |
5 | * Author : | |
6 | * Manikandan Pillai <mani.pillai@ti.com> | |
7 | * | |
8 | * Derived from Beagle Board and OMAP3 SDP code by | |
9 | * Richard Woodruff <r-woodruff2@ti.com> | |
10 | * Syed Mohammed Khasim <khasim@ti.com> | |
11 | * | |
12 | * This program is free software; you can redistribute it and/or | |
13 | * modify it under the terms of the GNU General Public License as | |
14 | * published by the Free Software Foundation; either version 2 of | |
15 | * the License, or (at your option) any later version. | |
16 | * | |
17 | * This program is distributed in the hope that it will be useful, | |
18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
20 | * GNU General Public License for more details. | |
21 | * | |
22 | * You should have received a copy of the GNU General Public License | |
23 | * along with this program; if not, write to the Free Software | |
24 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, | |
25 | * MA 02111-1307 USA | |
26 | */ | |
27 | ||
28 | #include <common.h> | |
29 | #include <asm/io.h> | |
30 | #include <asm/arch/clocks.h> | |
31 | #include <asm/arch/clocks_omap3.h> | |
32 | #include <asm/arch/mem.h> | |
33 | #include <asm/arch/sys_proto.h> | |
34 | #include <environment.h> | |
35 | #include <command.h> | |
36 | ||
37 | /****************************************************************************** | |
38 | * get_sys_clk_speed() - determine reference oscillator speed | |
39 | * based on known 32kHz clock and gptimer. | |
40 | *****************************************************************************/ | |
41 | u32 get_osc_clk_speed(void) | |
42 | { | |
b74064a0 | 43 | u32 start, cstart, cend, cdiff, cdiv, val; |
97a099ea DB |
44 | struct prcm *prcm_base = (struct prcm *)PRCM_BASE; |
45 | struct prm *prm_base = (struct prm *)PRM_BASE; | |
46 | struct gptimer *gpt1_base = (struct gptimer *)OMAP34XX_GPT1; | |
47 | struct s32ktimer *s32k_base = (struct s32ktimer *)SYNC_32KTIMER_BASE; | |
5ed3e865 DB |
48 | |
49 | val = readl(&prm_base->clksrc_ctrl); | |
50 | ||
b74064a0 SP |
51 | if (val & SYSCLKDIV_2) |
52 | cdiv = 2; | |
53 | else if (val & SYSCLKDIV_1) | |
54 | cdiv = 1; | |
55 | else | |
56 | /* | |
57 | * Should never reach here! (Assume divider as 1) | |
58 | */ | |
59 | cdiv = 1; | |
5ed3e865 DB |
60 | |
61 | /* enable timer2 */ | |
62 | val = readl(&prcm_base->clksel_wkup) | CLKSEL_GPT1; | |
63 | ||
64 | /* select sys_clk for GPT1 */ | |
65 | writel(val, &prcm_base->clksel_wkup); | |
66 | ||
67 | /* Enable I and F Clocks for GPT1 */ | |
68 | val = readl(&prcm_base->iclken_wkup) | EN_GPT1 | EN_32KSYNC; | |
69 | writel(val, &prcm_base->iclken_wkup); | |
b74064a0 | 70 | |
5ed3e865 DB |
71 | val = readl(&prcm_base->fclken_wkup) | EN_GPT1; |
72 | writel(val, &prcm_base->fclken_wkup); | |
73 | ||
74 | writel(0, &gpt1_base->tldr); /* start counting at 0 */ | |
75 | writel(GPT_EN, &gpt1_base->tclr); /* enable clock */ | |
76 | ||
77 | /* enable 32kHz source, determine sys_clk via gauging */ | |
78 | ||
79 | /* start time in 20 cycles */ | |
80 | start = 20 + readl(&s32k_base->s32k_cr); | |
81 | ||
82 | /* dead loop till start time */ | |
83 | while (readl(&s32k_base->s32k_cr) < start); | |
84 | ||
85 | /* get start sys_clk count */ | |
86 | cstart = readl(&gpt1_base->tcrr); | |
87 | ||
88 | /* wait for 40 cycles */ | |
89 | while (readl(&s32k_base->s32k_cr) < (start + 20)) ; | |
90 | cend = readl(&gpt1_base->tcrr); /* get end sys_clk count */ | |
91 | cdiff = cend - cstart; /* get elapsed ticks */ | |
92 | ||
b74064a0 SP |
93 | if (cdiv == 2) |
94 | { | |
95 | cdiff *= 2; | |
96 | } | |
97 | ||
5ed3e865 DB |
98 | /* based on number of ticks assign speed */ |
99 | if (cdiff > 19000) | |
100 | return S38_4M; | |
101 | else if (cdiff > 15200) | |
102 | return S26M; | |
103 | else if (cdiff > 13000) | |
104 | return S24M; | |
105 | else if (cdiff > 9000) | |
106 | return S19_2M; | |
107 | else if (cdiff > 7600) | |
108 | return S13M; | |
109 | else | |
110 | return S12M; | |
111 | } | |
112 | ||
113 | /****************************************************************************** | |
114 | * get_sys_clkin_sel() - returns the sys_clkin_sel field value based on | |
115 | * input oscillator clock frequency. | |
116 | *****************************************************************************/ | |
117 | void get_sys_clkin_sel(u32 osc_clk, u32 *sys_clkin_sel) | |
118 | { | |
119 | switch(osc_clk) { | |
120 | case S38_4M: | |
121 | *sys_clkin_sel = 4; | |
122 | break; | |
123 | case S26M: | |
124 | *sys_clkin_sel = 3; | |
125 | break; | |
126 | case S19_2M: | |
127 | *sys_clkin_sel = 2; | |
128 | break; | |
129 | case S13M: | |
130 | *sys_clkin_sel = 1; | |
131 | break; | |
132 | case S12M: | |
133 | default: | |
134 | *sys_clkin_sel = 0; | |
135 | } | |
136 | } | |
137 | ||
138 | /****************************************************************************** | |
139 | * prcm_init() - inits clocks for PRCM as defined in clocks.h | |
140 | * called from SRAM, or Flash (using temp SRAM stack). | |
141 | *****************************************************************************/ | |
142 | void prcm_init(void) | |
143 | { | |
144 | void (*f_lock_pll) (u32, u32, u32, u32); | |
145 | int xip_safe, p0, p1, p2, p3; | |
146 | u32 osc_clk = 0, sys_clkin_sel; | |
cba0b778 | 147 | u32 clk_index, sil_index = 0; |
97a099ea DB |
148 | struct prm *prm_base = (struct prm *)PRM_BASE; |
149 | struct prcm *prcm_base = (struct prcm *)PRCM_BASE; | |
5ed3e865 DB |
150 | dpll_param *dpll_param_p; |
151 | ||
152 | f_lock_pll = (void *) ((u32) &_end_vect - (u32) &_start + | |
153 | SRAM_VECT_CODE); | |
154 | ||
155 | xip_safe = is_running_in_sram(); | |
156 | ||
157 | /* | |
158 | * Gauge the input clock speed and find out the sys_clkin_sel | |
159 | * value corresponding to the input clock. | |
160 | */ | |
161 | osc_clk = get_osc_clk_speed(); | |
162 | get_sys_clkin_sel(osc_clk, &sys_clkin_sel); | |
163 | ||
164 | /* set input crystal speed */ | |
165 | sr32(&prm_base->clksel, 0, 3, sys_clkin_sel); | |
166 | ||
167 | /* If the input clock is greater than 19.2M always divide/2 */ | |
168 | if (sys_clkin_sel > 2) { | |
169 | /* input clock divider */ | |
170 | sr32(&prm_base->clksrc_ctrl, 6, 2, 2); | |
171 | clk_index = sys_clkin_sel / 2; | |
172 | } else { | |
173 | /* input clock divider */ | |
174 | sr32(&prm_base->clksrc_ctrl, 6, 2, 1); | |
175 | clk_index = sys_clkin_sel; | |
176 | } | |
177 | ||
178 | /* | |
179 | * The DPLL tables are defined according to sysclk value and | |
180 | * silicon revision. The clk_index value will be used to get | |
181 | * the values for that input sysclk from the DPLL param table | |
182 | * and sil_index will get the values for that SysClk for the | |
183 | * appropriate silicon rev. | |
184 | */ | |
cba0b778 SP |
185 | if (get_cpu_rev()) |
186 | sil_index = 1; | |
5ed3e865 DB |
187 | |
188 | /* Unlock MPU DPLL (slows things down, and needed later) */ | |
189 | sr32(&prcm_base->clken_pll_mpu, 0, 3, PLL_LOW_POWER_BYPASS); | |
190 | wait_on_value(ST_MPU_CLK, 0, &prcm_base->idlest_pll_mpu, LDELAY); | |
191 | ||
192 | /* Getting the base address of Core DPLL param table */ | |
193 | dpll_param_p = (dpll_param *) get_core_dpll_param(); | |
194 | ||
195 | /* Moving it to the right sysclk and ES rev base */ | |
196 | dpll_param_p = dpll_param_p + 3 * clk_index + sil_index; | |
197 | if (xip_safe) { | |
198 | /* | |
199 | * CORE DPLL | |
200 | * sr32(CM_CLKSEL2_EMU) set override to work when asleep | |
201 | */ | |
202 | sr32(&prcm_base->clken_pll, 0, 3, PLL_FAST_RELOCK_BYPASS); | |
203 | wait_on_value(ST_CORE_CLK, 0, &prcm_base->idlest_ckgen, | |
204 | LDELAY); | |
205 | ||
206 | /* | |
207 | * For OMAP3 ES1.0 Errata 1.50, default value directly doesn't | |
208 | * work. write another value and then default value. | |
209 | */ | |
210 | ||
211 | /* m3x2 */ | |
212 | sr32(&prcm_base->clksel1_emu, 16, 5, CORE_M3X2 + 1); | |
213 | /* m3x2 */ | |
214 | sr32(&prcm_base->clksel1_emu, 16, 5, CORE_M3X2); | |
215 | /* Set M2 */ | |
216 | sr32(&prcm_base->clksel1_pll, 27, 2, dpll_param_p->m2); | |
217 | /* Set M */ | |
218 | sr32(&prcm_base->clksel1_pll, 16, 11, dpll_param_p->m); | |
219 | /* Set N */ | |
220 | sr32(&prcm_base->clksel1_pll, 8, 7, dpll_param_p->n); | |
221 | /* 96M Src */ | |
222 | sr32(&prcm_base->clksel1_pll, 6, 1, 0); | |
223 | /* ssi */ | |
224 | sr32(&prcm_base->clksel_core, 8, 4, CORE_SSI_DIV); | |
225 | /* fsusb */ | |
226 | sr32(&prcm_base->clksel_core, 4, 2, CORE_FUSB_DIV); | |
227 | /* l4 */ | |
228 | sr32(&prcm_base->clksel_core, 2, 2, CORE_L4_DIV); | |
229 | /* l3 */ | |
230 | sr32(&prcm_base->clksel_core, 0, 2, CORE_L3_DIV); | |
231 | /* gfx */ | |
232 | sr32(&prcm_base->clksel_gfx, 0, 3, GFX_DIV); | |
233 | /* reset mgr */ | |
234 | sr32(&prcm_base->clksel_wkup, 1, 2, WKUP_RSM); | |
235 | /* FREQSEL */ | |
236 | sr32(&prcm_base->clken_pll, 4, 4, dpll_param_p->fsel); | |
237 | /* lock mode */ | |
238 | sr32(&prcm_base->clken_pll, 0, 3, PLL_LOCK); | |
239 | ||
240 | wait_on_value(ST_CORE_CLK, 1, &prcm_base->idlest_ckgen, | |
241 | LDELAY); | |
242 | } else if (is_running_in_flash()) { | |
243 | /* | |
244 | * if running from flash, jump to small relocated code | |
245 | * area in SRAM. | |
246 | */ | |
247 | p0 = readl(&prcm_base->clken_pll); | |
248 | sr32(&p0, 0, 3, PLL_FAST_RELOCK_BYPASS); | |
249 | sr32(&p0, 4, 4, dpll_param_p->fsel); /* FREQSEL */ | |
250 | ||
251 | p1 = readl(&prcm_base->clksel1_pll); | |
252 | sr32(&p1, 27, 2, dpll_param_p->m2); /* Set M2 */ | |
253 | sr32(&p1, 16, 11, dpll_param_p->m); /* Set M */ | |
254 | sr32(&p1, 8, 7, dpll_param_p->n); /* Set N */ | |
255 | sr32(&p1, 6, 1, 0); /* set source for 96M */ | |
256 | ||
257 | p2 = readl(&prcm_base->clksel_core); | |
258 | sr32(&p2, 8, 4, CORE_SSI_DIV); /* ssi */ | |
259 | sr32(&p2, 4, 2, CORE_FUSB_DIV); /* fsusb */ | |
260 | sr32(&p2, 2, 2, CORE_L4_DIV); /* l4 */ | |
261 | sr32(&p2, 0, 2, CORE_L3_DIV); /* l3 */ | |
262 | ||
263 | p3 = (u32)&prcm_base->idlest_ckgen; | |
264 | ||
265 | (*f_lock_pll) (p0, p1, p2, p3); | |
266 | } | |
267 | ||
268 | /* PER DPLL */ | |
269 | sr32(&prcm_base->clken_pll, 16, 3, PLL_STOP); | |
270 | wait_on_value(ST_PERIPH_CLK, 0, &prcm_base->idlest_ckgen, LDELAY); | |
271 | ||
272 | /* Getting the base address to PER DPLL param table */ | |
273 | ||
274 | /* Set N */ | |
275 | dpll_param_p = (dpll_param *) get_per_dpll_param(); | |
276 | ||
277 | /* Moving it to the right sysclk base */ | |
278 | dpll_param_p = dpll_param_p + clk_index; | |
279 | ||
280 | /* | |
281 | * Errata 1.50 Workaround for OMAP3 ES1.0 only | |
282 | * If using default divisors, write default divisor + 1 | |
283 | * and then the actual divisor value | |
284 | */ | |
285 | sr32(&prcm_base->clksel1_emu, 24, 5, PER_M6X2 + 1); /* set M6 */ | |
286 | sr32(&prcm_base->clksel1_emu, 24, 5, PER_M6X2); /* set M6 */ | |
287 | sr32(&prcm_base->clksel_cam, 0, 5, PER_M5X2 + 1); /* set M5 */ | |
288 | sr32(&prcm_base->clksel_cam, 0, 5, PER_M5X2); /* set M5 */ | |
289 | sr32(&prcm_base->clksel_dss, 0, 5, PER_M4X2 + 1); /* set M4 */ | |
290 | sr32(&prcm_base->clksel_dss, 0, 5, PER_M4X2); /* set M4 */ | |
291 | sr32(&prcm_base->clksel_dss, 8, 5, PER_M3X2 + 1); /* set M3 */ | |
292 | sr32(&prcm_base->clksel_dss, 8, 5, PER_M3X2); /* set M3 */ | |
293 | sr32(&prcm_base->clksel3_pll, 0, 5, dpll_param_p->m2 + 1); /* set M2 */ | |
294 | sr32(&prcm_base->clksel3_pll, 0, 5, dpll_param_p->m2); /* set M2 */ | |
295 | /* Workaround end */ | |
296 | ||
297 | sr32(&prcm_base->clksel2_pll, 8, 11, dpll_param_p->m); /* set m */ | |
298 | sr32(&prcm_base->clksel2_pll, 0, 7, dpll_param_p->n); /* set n */ | |
299 | sr32(&prcm_base->clken_pll, 20, 4, dpll_param_p->fsel); /* FREQSEL */ | |
300 | sr32(&prcm_base->clken_pll, 16, 3, PLL_LOCK); /* lock mode */ | |
301 | wait_on_value(ST_PERIPH_CLK, 2, &prcm_base->idlest_ckgen, LDELAY); | |
302 | ||
303 | /* Getting the base address to MPU DPLL param table */ | |
304 | dpll_param_p = (dpll_param *) get_mpu_dpll_param(); | |
305 | ||
306 | /* Moving it to the right sysclk and ES rev base */ | |
307 | dpll_param_p = dpll_param_p + 3 * clk_index + sil_index; | |
308 | ||
309 | /* MPU DPLL (unlocked already) */ | |
310 | ||
311 | /* Set M2 */ | |
312 | sr32(&prcm_base->clksel2_pll_mpu, 0, 5, dpll_param_p->m2); | |
313 | /* Set M */ | |
314 | sr32(&prcm_base->clksel1_pll_mpu, 8, 11, dpll_param_p->m); | |
315 | /* Set N */ | |
316 | sr32(&prcm_base->clksel1_pll_mpu, 0, 7, dpll_param_p->n); | |
317 | /* FREQSEL */ | |
318 | sr32(&prcm_base->clken_pll_mpu, 4, 4, dpll_param_p->fsel); | |
319 | /* lock mode */ | |
320 | sr32(&prcm_base->clken_pll_mpu, 0, 3, PLL_LOCK); | |
321 | wait_on_value(ST_MPU_CLK, 1, &prcm_base->idlest_pll_mpu, LDELAY); | |
322 | ||
323 | /* Getting the base address to IVA DPLL param table */ | |
324 | dpll_param_p = (dpll_param *) get_iva_dpll_param(); | |
325 | ||
326 | /* Moving it to the right sysclk and ES rev base */ | |
327 | dpll_param_p = dpll_param_p + 3 * clk_index + sil_index; | |
328 | ||
329 | /* IVA DPLL (set to 12*20=240MHz) */ | |
330 | sr32(&prcm_base->clken_pll_iva2, 0, 3, PLL_STOP); | |
331 | wait_on_value(ST_IVA2_CLK, 0, &prcm_base->idlest_pll_iva2, LDELAY); | |
332 | /* set M2 */ | |
333 | sr32(&prcm_base->clksel2_pll_iva2, 0, 5, dpll_param_p->m2); | |
334 | /* set M */ | |
335 | sr32(&prcm_base->clksel1_pll_iva2, 8, 11, dpll_param_p->m); | |
336 | /* set N */ | |
337 | sr32(&prcm_base->clksel1_pll_iva2, 0, 7, dpll_param_p->n); | |
338 | /* FREQSEL */ | |
339 | sr32(&prcm_base->clken_pll_iva2, 4, 4, dpll_param_p->fsel); | |
340 | /* lock mode */ | |
341 | sr32(&prcm_base->clken_pll_iva2, 0, 3, PLL_LOCK); | |
342 | wait_on_value(ST_IVA2_CLK, 1, &prcm_base->idlest_pll_iva2, LDELAY); | |
343 | ||
344 | /* Set up GPTimers to sys_clk source only */ | |
345 | sr32(&prcm_base->clksel_per, 0, 8, 0xff); | |
346 | sr32(&prcm_base->clksel_wkup, 0, 1, 1); | |
347 | ||
348 | sdelay(5000); | |
349 | } | |
350 | ||
351 | /****************************************************************************** | |
352 | * peripheral_enable() - Enable the clks & power for perifs (GPT2, UART1,...) | |
353 | *****************************************************************************/ | |
354 | void per_clocks_enable(void) | |
355 | { | |
97a099ea | 356 | struct prcm *prcm_base = (struct prcm *)PRCM_BASE; |
5ed3e865 DB |
357 | |
358 | /* Enable GP2 timer. */ | |
359 | sr32(&prcm_base->clksel_per, 0, 1, 0x1); /* GPT2 = sys clk */ | |
360 | sr32(&prcm_base->iclken_per, 3, 1, 0x1); /* ICKen GPT2 */ | |
361 | sr32(&prcm_base->fclken_per, 3, 1, 0x1); /* FCKen GPT2 */ | |
362 | ||
363 | #ifdef CONFIG_SYS_NS16550 | |
364 | /* Enable UART1 clocks */ | |
365 | sr32(&prcm_base->fclken1_core, 13, 1, 0x1); | |
366 | sr32(&prcm_base->iclken1_core, 13, 1, 0x1); | |
367 | ||
368 | /* UART 3 Clocks */ | |
369 | sr32(&prcm_base->fclken_per, 11, 1, 0x1); | |
370 | sr32(&prcm_base->iclken_per, 11, 1, 0x1); | |
371 | #endif | |
708cfb74 TR |
372 | |
373 | #ifdef CONFIG_OMAP3_GPIO_2 | |
374 | sr32(&prcm_base->fclken_per, 13, 1, 1); | |
375 | sr32(&prcm_base->iclken_per, 13, 1, 1); | |
376 | #endif | |
377 | #ifdef CONFIG_OMAP3_GPIO_3 | |
378 | sr32(&prcm_base->fclken_per, 14, 1, 1); | |
379 | sr32(&prcm_base->iclken_per, 14, 1, 1); | |
380 | #endif | |
381 | #ifdef CONFIG_OMAP3_GPIO_4 | |
382 | sr32(&prcm_base->fclken_per, 15, 1, 1); | |
383 | sr32(&prcm_base->iclken_per, 15, 1, 1); | |
384 | #endif | |
385 | #ifdef CONFIG_OMAP3_GPIO_5 | |
386 | sr32(&prcm_base->fclken_per, 16, 1, 1); | |
387 | sr32(&prcm_base->iclken_per, 16, 1, 1); | |
388 | #endif | |
389 | #ifdef CONFIG_OMAP3_GPIO_6 | |
390 | sr32(&prcm_base->fclken_per, 17, 1, 1); | |
391 | sr32(&prcm_base->iclken_per, 17, 1, 1); | |
392 | #endif | |
393 | ||
5ed3e865 DB |
394 | #ifdef CONFIG_DRIVER_OMAP34XX_I2C |
395 | /* Turn on all 3 I2C clocks */ | |
396 | sr32(&prcm_base->fclken1_core, 15, 3, 0x7); | |
397 | sr32(&prcm_base->iclken1_core, 15, 3, 0x7); /* I2C1,2,3 = on */ | |
398 | #endif | |
399 | /* Enable the ICLK for 32K Sync Timer as its used in udelay */ | |
400 | sr32(&prcm_base->iclken_wkup, 2, 1, 0x1); | |
401 | ||
402 | sr32(&prcm_base->fclken_iva2, 0, 32, FCK_IVA2_ON); | |
403 | sr32(&prcm_base->fclken1_core, 0, 32, FCK_CORE1_ON); | |
404 | sr32(&prcm_base->iclken1_core, 0, 32, ICK_CORE1_ON); | |
405 | sr32(&prcm_base->iclken2_core, 0, 32, ICK_CORE2_ON); | |
406 | sr32(&prcm_base->fclken_wkup, 0, 32, FCK_WKUP_ON); | |
407 | sr32(&prcm_base->iclken_wkup, 0, 32, ICK_WKUP_ON); | |
408 | sr32(&prcm_base->fclken_dss, 0, 32, FCK_DSS_ON); | |
409 | sr32(&prcm_base->iclken_dss, 0, 32, ICK_DSS_ON); | |
410 | sr32(&prcm_base->fclken_cam, 0, 32, FCK_CAM_ON); | |
411 | sr32(&prcm_base->iclken_cam, 0, 32, ICK_CAM_ON); | |
412 | sr32(&prcm_base->fclken_per, 0, 32, FCK_PER_ON); | |
413 | sr32(&prcm_base->iclken_per, 0, 32, ICK_PER_ON); | |
414 | ||
415 | sdelay(1000); | |
416 | } |