]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - arch/arm/cpu/armv7/am33xx/clock.c
Merge remote branch 'remotes/kc/karo-tx6q' into karo-tx48
[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 #endif /* CONFIG_SPL_BUILD */
166
167 void mpu_pll_config(int m)
168 {
169         u32 clkmode, clksel, div_m2;
170
171         clkmode = readl(&cmwkup->clkmoddpllmpu);
172         clksel = readl(&cmwkup->clkseldpllmpu);
173         div_m2 = readl(&cmwkup->divm2dpllmpu);
174
175         /* Set the PLL to bypass Mode */
176         writel(PLL_BYPASS_MODE, &cmwkup->clkmoddpllmpu);
177         while (readl(&cmwkup->idlestdpllmpu) != ST_MN_BYPASS)
178                 ;
179
180         clksel &= ~CLK_SEL_MASK;
181         clksel |= (m << CLK_SEL_SHIFT) | MPUPLL_N;
182         writel(clksel, &cmwkup->clkseldpllmpu);
183
184         div_m2 &= ~CLK_DIV_MASK;
185         div_m2 |= MPUPLL_M2;
186         writel(div_m2, &cmwkup->divm2dpllmpu);
187
188         clkmode &= ~CLK_MODE_MASK;
189         clkmode |= CLK_MODE_SEL;
190         writel(clkmode, &cmwkup->clkmoddpllmpu);
191
192         while (readl(&cmwkup->idlestdpllmpu) != ST_DPLL_CLK)
193                 ;
194 }
195
196 static void core_pll_config(int m)
197 {
198         u32 clkmode, clksel, div_m4, div_m5, div_m6;
199
200         clkmode = readl(&cmwkup->clkmoddpllcore);
201         clksel = readl(&cmwkup->clkseldpllcore);
202         div_m4 = readl(&cmwkup->divm4dpllcore);
203         div_m5 = readl(&cmwkup->divm5dpllcore);
204         div_m6 = readl(&cmwkup->divm6dpllcore);
205
206         /* Set the PLL to bypass Mode */
207         writel(PLL_BYPASS_MODE, &cmwkup->clkmoddpllcore);
208
209         while (readl(&cmwkup->idlestdpllcore) != ST_MN_BYPASS)
210                 ;
211
212         clksel &= ~CLK_SEL_MASK;
213         clksel |= ((m << CLK_SEL_SHIFT) | COREPLL_N);
214         writel(clksel, &cmwkup->clkseldpllcore);
215
216         div_m4 &= ~CLK_DIV_MASK;
217         div_m4 |= COREPLL_M4;
218         writel(div_m4, &cmwkup->divm4dpllcore);
219
220         div_m5 &= ~CLK_DIV_MASK;
221         div_m5 |= COREPLL_M5;
222         writel(div_m5, &cmwkup->divm5dpllcore);
223
224         div_m6 &= ~CLK_DIV_MASK;
225         div_m6 |= COREPLL_M6;
226         writel(div_m6, &cmwkup->divm6dpllcore);
227
228         clkmode &= ~CLK_MODE_MASK;
229         clkmode |= CLK_MODE_SEL;
230         writel(clkmode, &cmwkup->clkmoddpllcore);
231
232         while (readl(&cmwkup->idlestdpllcore) != ST_DPLL_CLK)
233                 ;
234 }
235
236 static void per_pll_config(int m)
237 {
238         u32 clkmode, clksel, div_m2;
239
240         clkmode = readl(&cmwkup->clkmoddpllper);
241         clksel = readl(&cmwkup->clkseldpllper);
242         div_m2 = readl(&cmwkup->divm2dpllper);
243
244         /* Set the PLL to bypass Mode */
245         writel(PLL_BYPASS_MODE, &cmwkup->clkmoddpllper);
246
247         while (readl(&cmwkup->idlestdpllper) != ST_MN_BYPASS)
248                 ;
249
250         clksel &= ~CLK_SEL_MASK;
251         clksel |= (m << CLK_SEL_SHIFT) | PERPLL_N;
252         writel(clksel, &cmwkup->clkseldpllper);
253
254         div_m2 &= ~CLK_DIV2_MASK;
255         div_m2 |= PERPLL_M2;
256         writel(div_m2, &cmwkup->divm2dpllper);
257
258         clkmode &= ~CLK_MODE_MASK;
259         clkmode |= CLK_MODE_SEL;
260         writel(clkmode, &cmwkup->clkmoddpllper);
261
262         while (readl(&cmwkup->idlestdpllper) != ST_DPLL_CLK)
263                 ;
264
265         writel(DPLL_CLKDCOLDO_GATE_CTRL, &cmwkup->clkdcoldodpllper);
266 }
267
268 static void disp_pll_config(int m)
269 {
270         u32 clkmode, clksel, div_m2;
271
272         clkmode = readl(&cmwkup->clkmoddplldisp);
273         clksel = readl(&cmwkup->clkseldplldisp);
274         div_m2 = readl(&cmwkup->divm2dplldisp);
275
276         /* Set the PLL to bypass Mode */
277         writel(PLL_BYPASS_MODE, &cmwkup->clkmoddplldisp);
278
279         while (!(readl(&cmwkup->idlestdplldisp) & ST_MN_BYPASS))
280                 ;
281
282         clksel &= ~CLK_SEL_MASK;
283         clksel |= (m << CLK_SEL_SHIFT) | DISPPLL_N;
284         writel(clksel, &cmwkup->clkseldplldisp);
285
286         div_m2 &= ~CLK_DIV2_MASK;
287         div_m2 |= DISPPLL_M2;
288         writel(div_m2, &cmwkup->divm2dplldisp);
289
290         clkmode &= ~CLK_MODE_MASK;
291         clkmode |= CLK_MODE_SEL;
292         writel(clkmode, &cmwkup->clkmoddplldisp);
293
294         while (!(readl(&cmwkup->idlestdplldisp) & ST_DPLL_CLK))
295                 ;
296 }
297
298 void ddr_pll_config(unsigned int ddrpll_m)
299 {
300         u32 clkmode, clksel, div_m2;
301
302         clkmode = readl(&cmwkup->clkmoddpllddr);
303         clksel = readl(&cmwkup->clkseldpllddr);
304         div_m2 = readl(&cmwkup->divm2dpllddr);
305
306         /* Set the PLL to bypass Mode */
307         clkmode &= ~CLK_MODE_MASK;
308         clkmode |= PLL_BYPASS_MODE;
309         writel(clkmode, &cmwkup->clkmoddpllddr);
310
311         /* Wait till bypass mode is enabled */
312         while (!(readl(&cmwkup->idlestdpllddr) & ST_MN_BYPASS))
313                 ;
314
315         clksel &= ~CLK_SEL_MASK;
316         clksel |= (ddrpll_m << CLK_SEL_SHIFT) | DDRPLL_N;
317         writel(clksel, &cmwkup->clkseldpllddr);
318
319         div_m2 &= ~CLK_DIV_MASK;
320         div_m2 |= DDRPLL_M2;
321         writel(div_m2, &cmwkup->divm2dpllddr);
322
323         clkmode &= ~CLK_MODE_MASK;
324         clkmode |= CLK_MODE_SEL;
325         writel(clkmode, &cmwkup->clkmoddpllddr);
326
327         /* Wait till dpll is locked */
328         while ((readl(&cmwkup->idlestdpllddr) & ST_DPLL_CLK) != ST_DPLL_CLK)
329                 ;
330 }
331
332 #ifdef CONFIG_SPL_BUILD
333 void enable_emif_clocks(void)
334 {
335         /* Enable the  EMIF_FW Functional clock */
336         writel(PRCM_MOD_EN, &cmper->emiffwclkctrl);
337         /* Enable EMIF0 Clock */
338         writel(PRCM_MOD_EN, &cmper->emifclkctrl);
339         /* Poll if module is functional */
340         while ((readl(&cmper->emifclkctrl)) != PRCM_MOD_EN)
341                 ;
342 }
343
344 /*
345  * Configure the PLL/PRCM for necessary peripherals
346  */
347 void pll_init()
348 {
349         mpu_pll_config(MPUPLL_M);
350         core_pll_config(COREPLL_M);
351         per_pll_config(PERPLL_M);
352         disp_pll_config(DISPPLL_M);
353
354         /* Enable the required interconnect clocks */
355         enable_interface_clocks();
356
357         /* Power domain wake up transition */
358         power_domain_wkup_transition();
359
360         /* Enable the required peripherals */
361         enable_per_clocks();
362 }
363 #endif
364
365 #define M(mn) (((mn) & CLK_SEL_MASK) >> CLK_SEL_SHIFT)
366 #define N(mn) ((mn) & CLK_DIV2_MASK)
367
368 unsigned long __clk_get_rate(u32 m_n, u32 div_m2)
369 {
370         unsigned long rate;
371
372         div_m2 &= CLK_DIV_MASK;
373         debug("M=%u N=%u M2=%u\n", M(m_n), N(m_n), div_m2);
374         rate = V_OSCK / 1000 * M(m_n) / (N(m_n) + 1) / div_m2;
375         debug("CLK = %lu.%03luMHz\n", rate / 1000, rate % 1000);
376         return rate * 1000;
377 }
378
379 unsigned long lcdc_clk_rate(void)
380 {
381         return clk_get_rate(cmwkup, disp);
382 }
383
384 unsigned long mpu_clk_rate(void)
385 {
386         return clk_get_rate(cmwkup, mpu);
387 }
388
389 enum {
390         CLK_MPU_PLL,
391         CLK_CORE_PLL,
392         CLK_PER_PLL,
393         CLK_DISP_PLL,
394         CLK_GPMC,
395 };
396
397 static struct clk_lookup {
398         const char *name;
399         unsigned int index;
400 } am33xx_clk_lookup[] = {
401         { "mpu", CLK_MPU_PLL, },
402         { "core", CLK_CORE_PLL, },
403         { "per", CLK_PER_PLL, },
404         { "lcdc", CLK_DISP_PLL, },
405         { "gpmc", CLK_GPMC, },
406 };
407
408 #define print_pll(dom, pll) {                           \
409         u32 __pll = clk_get_rate(dom, pll);             \
410         printf("%-12s %4d.%03d MHz\n", #pll,            \
411                 __pll / 1000000, __pll / 1000 % 1000);  \
412         }
413
414 #define print_pll2(dom, n, pll) {                       \
415         u32 __m_n = readl(&(dom)->clkseldpll##pll);     \
416         u32 __div = readl(&(dom)->divm##n##dpll##pll);  \
417         u32 __pll = __clk_get_rate(__m_n, __div);       \
418         printf("%-12s %4d.%03d MHz\n", #pll "_m" #n,    \
419                 __pll / 1000000, __pll / 1000 % 1000);  \
420         }
421
422 static void do_showclocks(void)
423 {
424         print_pll(cmwkup, mpu);
425         print_pll2(cmwkup, 4, core);
426         print_pll2(cmwkup, 5, core);
427         print_pll2(cmwkup, 6, core);
428         print_pll(cmwkup, ddr);
429         print_pll(cmwkup, per);
430         print_pll(cmwkup, disp);
431 }
432
433 int do_clocks(cmd_tbl_t *cmdtp, int flag, int argc,
434         char *const argv[])
435 {
436         int i;
437         unsigned long freq;
438         unsigned long __attribute__((unused)) ref = ~0UL;
439
440         if (argc < 2) {
441                 do_showclocks();
442                 return CMD_RET_SUCCESS;
443         } else if (argc == 2 || argc > 4) {
444                 return CMD_RET_USAGE;
445         }
446
447         freq = simple_strtoul(argv[2], NULL, 0);
448         if (freq < 1000) {
449                 printf("Invalid clock frequency %lu\n", freq);
450                 return CMD_RET_FAILURE;
451         }
452         if (argc > 3) {
453                 ref = simple_strtoul(argv[3], NULL, 0);
454         }
455         for (i = 0; i < ARRAY_SIZE(am33xx_clk_lookup); i++) {
456                 if (strcasecmp(argv[1], am33xx_clk_lookup[i].name) == 0) {
457                         switch (am33xx_clk_lookup[i].index) {
458                         case CLK_MPU_PLL:
459                                 mpu_pll_config(freq / 1000000);
460                                 break;
461                         case CLK_CORE_PLL:
462                                 core_pll_config(freq / 1000000);
463                                 break;
464                         case CLK_PER_PLL:
465                                 per_pll_config(freq / 1000000);
466                                 break;
467                         case CLK_DISP_PLL:
468                                 disp_pll_config(freq / 1000000);
469                                 break;
470                         default:
471                                 printf("Cannot change %s clock\n",
472                                         am33xx_clk_lookup[i].name);
473                                 return CMD_RET_FAILURE;
474                         }
475
476                         printf("%s clock set to %lu.%03lu MHz\n",
477                                 am33xx_clk_lookup[i].name,
478                                 freq / 1000000, freq / 1000 % 1000);
479                         return CMD_RET_SUCCESS;
480                 }
481         }
482         if (i == ARRAY_SIZE(am33xx_clk_lookup)) {
483                 printf("clock %s not found; supported clocks are:\n", argv[1]);
484                 for (i = 0; i < ARRAY_SIZE(am33xx_clk_lookup); i++) {
485                         printf("\t%s\n", am33xx_clk_lookup[i].name);
486                 }
487         } else {
488                 printf("Failed to set clock %s to %s MHz\n",
489                         argv[1], argv[2]);
490         }
491         return CMD_RET_FAILURE;
492 }
493
494 U_BOOT_CMD(
495         clocks, 4, 0, do_clocks,
496         "display/set clocks",
497         "                    - display clock settings\n"
498         "clocks <clkname> <freq>    - set clock <clkname> to <freq> Hz"
499 );