]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - arch/arm/cpu/armv7/am33xx/clock_am33xx.c
merged tx6dl-devel into denx master branch
[karo-tx-uboot.git] / arch / arm / cpu / armv7 / am33xx / clock_am33xx.c
1 /*
2  * clock_am33xx.c
3  *
4  * clocks for AM33XX based boards
5  *
6  * Copyright (C) 2013, Texas Instruments, Incorporated - http://www.ti.com/
7  *
8  * SPDX-License-Identifier:     GPL-2.0+
9  */
10
11 #include <common.h>
12 #include <asm/arch/cpu.h>
13 #include <asm/arch/clock.h>
14 #include <asm/arch/hardware.h>
15 #include <asm/io.h>
16
17 #define PRCM_MOD_EN             0x2
18 #define PRCM_FORCE_WAKEUP       0x2
19 #define PRCM_FUNCTL             0x0
20
21 #define PRCM_EMIF_CLK_ACTIVITY  BIT(2)
22 #define PRCM_L3_GCLK_ACTIVITY   BIT(4)
23
24 #define PLL_BYPASS_MODE         0x4
25 #define ST_MN_BYPASS            0x00000100
26 #define ST_DPLL_CLK             0x00000001
27 #define CLK_SEL_MASK            0x7ffff
28 #define CLK_DIV_MASK            0x1f
29 #define CLK_DIV2_MASK           0x7f
30 #define CLK_SEL_SHIFT           0x8
31 #define CLK_MODE_MASK           0x7
32 #define CLK_MODE_SEL            0x7
33 #define DPLL_CLKDCOLDO_GATE_CTRL 0x300
34
35
36 #define OSC     (V_OSCK/1000000)
37
38 #define MPUPLL_M        CONFIG_SYS_MPUCLK
39 #define MPUPLL_N        (OSC-1)
40 #define MPUPLL_M2       1
41
42 /* Core PLL Fdll = 1 GHZ, */
43 #define COREPLL_M       1000
44 #define COREPLL_N       (OSC-1)
45
46 #define COREPLL_M4      10      /* CORE_CLKOUTM4 = 200 MHZ */
47 #define COREPLL_M5      8       /* CORE_CLKOUTM5 = 250 MHZ */
48 #define COREPLL_M6      4       /* CORE_CLKOUTM6 = 500 MHZ */
49
50 /*
51  * USB PHY clock is 960 MHZ. Since, this comes directly from Fdll, Fdll
52  * frequency needs to be set to 960 MHZ. Hence,
53  * For clkout = 192 MHZ, Fdll = 960 MHZ, divider values are given below
54  */
55 #define PERPLL_M        960
56 #define PERPLL_N        (OSC-1)
57 #define PERPLL_M2       5
58
59 /* DDR Freq is 266 MHZ for now */
60 /* Set Fdll = 400 MHZ , Fdll = M * 2 * CLKINP/ N + 1; clkout = Fdll /(2 * M2) */
61 #define DDRPLL_M        266
62 #define DDRPLL_N        (OSC-1)
63 #define DDRPLL_M2       1
64
65 const struct cm_perpll *cmper = (struct cm_perpll *)CM_PER;
66 const struct cm_wkuppll *cmwkup = (struct cm_wkuppll *)CM_WKUP;
67 const struct cm_dpll *cmdpll = (struct cm_dpll *)CM_DPLL;
68 const struct cm_rtc *cmrtc = (struct cm_rtc *)CM_RTC;
69
70 #ifdef CONFIG_SPL_BUILD
71 #define enable_clk(reg, val) __enable_clk(#reg, &reg, val)
72
73 static void __enable_clk(const char *name, const void *reg, u32 mask)
74 {
75         unsigned long timeout = 10000000;
76
77         writel(mask, reg);
78         while (readl(reg) != mask)
79                 /* poor man's timeout, since timers not initialized */
80                 if (timeout-- == 0)
81                         /* no error message, since console not yet available */
82                         break;
83 }
84
85 static void enable_interface_clocks(void)
86 {
87         /* Enable all the Interconnect Modules */
88         enable_clk(cmper->l3clkctrl, PRCM_MOD_EN);
89         enable_clk(cmper->l4lsclkctrl, PRCM_MOD_EN);
90         enable_clk(cmper->l4fwclkctrl, PRCM_MOD_EN);
91         enable_clk(cmwkup->wkl4wkclkctrl, PRCM_MOD_EN);
92         enable_clk(cmper->l3instrclkctrl, PRCM_MOD_EN);
93         enable_clk(cmper->l4hsclkctrl, PRCM_MOD_EN);
94 #ifdef CONFIG_HW_WATCHDOG
95         enable_clk(cmwkup->wdtimer1ctrl, PRCM_MOD_EN);
96 #endif
97         /* GPIO0 */
98         enable_clk(cmwkup->wkgpio0clkctrl, PRCM_MOD_EN);
99 }
100
101 /*
102  * Force power domain wake up transition
103  * Ensure that the corresponding interface clock is active before
104  * using the peripheral
105  */
106 static void power_domain_wkup_transition(void)
107 {
108         writel(PRCM_FORCE_WAKEUP, &cmper->l3clkstctrl);
109         writel(PRCM_FORCE_WAKEUP, &cmper->l4lsclkstctrl);
110         writel(PRCM_FORCE_WAKEUP, &cmwkup->wkclkstctrl);
111         writel(PRCM_FORCE_WAKEUP, &cmper->l4fwclkstctrl);
112         writel(PRCM_FORCE_WAKEUP, &cmper->l3sclkstctrl);
113 }
114
115 /*
116  * Enable the peripheral clock for required peripherals
117  */
118 static void enable_per_clocks(void)
119 {
120         /* Enable the control module though RBL would have done it*/
121         enable_clk(cmwkup->wkctrlclkctrl, PRCM_MOD_EN);
122         /* Enable the timer2 clock */
123         enable_clk(cmper->timer2clkctrl, PRCM_MOD_EN);
124         /* Select the Master osc 24 MHZ as Timer2 clock source */
125         writel(0x1, &cmdpll->clktimer2clk);
126
127 #ifdef CONFIG_SYS_NS16550_COM1
128         /* UART0 */
129         enable_clk(cmwkup->wkup_uart0ctrl, PRCM_MOD_EN);
130 #endif
131 #ifdef CONFIG_SYS_NS16550_COM2
132         enable_clk(cmper->uart1clkctrl, PRCM_MOD_EN);
133 #endif
134 #ifdef CONFIG_SYS_NS16550_COM3
135         enable_clk(cmper->uart2clkctrl, PRCM_MOD_EN);
136 #endif
137 #ifdef CONFIG_SYS_NS16550_COM4
138         enable_clk(cmper->uart3clkctrl, PRCM_MOD_EN);
139 #endif
140 #ifdef CONFIG_SYS_NS16550_COM5
141         enable_clk(cmper->uart4clkctrl, PRCM_MOD_EN);
142 #endif
143 #ifdef CONFIG_SYS_NS16550_COM6
144         enable_clk(cmper->uart5clkctrl, PRCM_MOD_EN);
145 #endif
146         /* GPMC */
147         enable_clk(cmper->gpmcclkctrl, PRCM_MOD_EN);
148
149         /* ELM */
150         enable_clk(cmper->elmclkctrl, PRCM_MOD_EN);
151
152         /* Ethernet */
153         enable_clk(cmper->cpswclkstctrl, PRCM_MOD_EN);
154         enable_clk(cmper->cpgmac0clkctrl, PRCM_MOD_EN);
155
156         /* MMC */
157 #ifndef CONFIG_OMAP_MMC_DEV_0
158         enable_clk(cmper->mmc0clkctrl, PRCM_MOD_EN);
159 #endif
160 #ifdef CONFIG_OMAP_MMC_DEV_1
161         enable_clk(cmper->mmc1clkctrl, PRCM_MOD_EN);
162 #endif
163         /* LCD */
164         enable_clk(cmper->lcdclkctrl, PRCM_MOD_EN);
165
166         /* MMC1 */
167         writel(PRCM_MOD_EN, &cmper->mmc1clkctrl);
168         while (readl(&cmper->mmc1clkctrl) != PRCM_MOD_EN)
169                 ;
170
171         /* i2c0 */
172         enable_clk(cmwkup->wkup_i2c0ctrl, PRCM_MOD_EN);
173
174         /* GPIO1-3 */
175         enable_clk(cmper->gpio1clkctrl, PRCM_MOD_EN);
176         enable_clk(cmper->gpio2clkctrl, PRCM_MOD_EN);
177         enable_clk(cmper->gpio3clkctrl, PRCM_MOD_EN);
178
179         /* i2c1 */
180         enable_clk(cmper->i2c1clkctrl, PRCM_MOD_EN);
181
182         /* spi0 */
183         enable_clk(cmper->spi0clkctrl, PRCM_MOD_EN);
184
185         /* rtc */
186         enable_clk(cmrtc->rtcclkctrl, PRCM_MOD_EN);
187
188         /* usb0 */
189         enable_clk(cmper->usb0clkctrl, PRCM_MOD_EN);
190 }
191 #endif /* CONFIG_SPL_BUILD */
192
193 void mpu_pll_config_val(int mpull_m)
194 {
195         u32 clkmode, clksel, div_m2;
196
197         clkmode = readl(&cmwkup->clkmoddpllmpu);
198         clksel = readl(&cmwkup->clkseldpllmpu);
199         div_m2 = readl(&cmwkup->divm2dpllmpu);
200
201         /* Set the PLL to bypass Mode */
202         writel(PLL_BYPASS_MODE, &cmwkup->clkmoddpllmpu);
203         while (readl(&cmwkup->idlestdpllmpu) != ST_MN_BYPASS)
204                 ;
205
206         clksel &= ~CLK_SEL_MASK;
207         clksel |= (mpull_m << CLK_SEL_SHIFT) | MPUPLL_N;
208         writel(clksel, &cmwkup->clkseldpllmpu);
209
210         div_m2 &= ~CLK_DIV_MASK;
211         div_m2 |= MPUPLL_M2;
212         writel(div_m2, &cmwkup->divm2dpllmpu);
213
214         clkmode &= ~CLK_MODE_MASK;
215         clkmode |= CLK_MODE_SEL;
216         writel(clkmode, &cmwkup->clkmoddpllmpu);
217
218         while (readl(&cmwkup->idlestdpllmpu) != ST_DPLL_CLK)
219                 ;
220 }
221
222 void mpu_pll_config(void)
223 {
224         mpu_pll_config_val(CONFIG_SYS_MPUCLK);
225 }
226
227 static void core_pll_config_val(int m)
228 {
229         u32 clkmode, clksel, div_m4, div_m5, div_m6;
230
231         clkmode = readl(&cmwkup->clkmoddpllcore);
232         clksel = readl(&cmwkup->clkseldpllcore);
233         div_m4 = readl(&cmwkup->divm4dpllcore);
234         div_m5 = readl(&cmwkup->divm5dpllcore);
235         div_m6 = readl(&cmwkup->divm6dpllcore);
236
237         /* Set the PLL to bypass Mode */
238         writel(PLL_BYPASS_MODE, &cmwkup->clkmoddpllcore);
239
240         while (readl(&cmwkup->idlestdpllcore) != ST_MN_BYPASS)
241                 ;
242
243         clksel &= ~CLK_SEL_MASK;
244         clksel |= ((m << CLK_SEL_SHIFT) | COREPLL_N);
245         writel(clksel, &cmwkup->clkseldpllcore);
246
247         div_m4 &= ~CLK_DIV_MASK;
248         div_m4 |= COREPLL_M4;
249         writel(div_m4, &cmwkup->divm4dpllcore);
250
251         div_m5 &= ~CLK_DIV_MASK;
252         div_m5 |= COREPLL_M5;
253         writel(div_m5, &cmwkup->divm5dpllcore);
254
255         div_m6 &= ~CLK_DIV_MASK;
256         div_m6 |= COREPLL_M6;
257         writel(div_m6, &cmwkup->divm6dpllcore);
258
259         clkmode &= ~CLK_MODE_MASK;
260         clkmode |= CLK_MODE_SEL;
261         writel(clkmode, &cmwkup->clkmoddpllcore);
262
263         while (readl(&cmwkup->idlestdpllcore) != ST_DPLL_CLK)
264                 ;
265 }
266
267 static inline void core_pll_config(void)
268 {
269         core_pll_config_val(COREPLL_M);
270 }
271
272 static void per_pll_config_val(int m)
273 {
274         u32 clkmode, clksel, div_m2;
275
276         clkmode = readl(&cmwkup->clkmoddpllper);
277         clksel = readl(&cmwkup->clkseldpllper);
278         div_m2 = readl(&cmwkup->divm2dpllper);
279
280         /* Set the PLL to bypass Mode */
281         writel(PLL_BYPASS_MODE, &cmwkup->clkmoddpllper);
282
283         while (readl(&cmwkup->idlestdpllper) != ST_MN_BYPASS)
284                 ;
285
286         clksel &= ~CLK_SEL_MASK;
287         clksel |= (m << CLK_SEL_SHIFT) | PERPLL_N;
288         writel(clksel, &cmwkup->clkseldpllper);
289
290         div_m2 &= ~CLK_DIV2_MASK;
291         div_m2 |= PERPLL_M2;
292         writel(div_m2, &cmwkup->divm2dpllper);
293
294         clkmode &= ~CLK_MODE_MASK;
295         clkmode |= CLK_MODE_SEL;
296         writel(clkmode, &cmwkup->clkmoddpllper);
297
298         while (readl(&cmwkup->idlestdpllper) != ST_DPLL_CLK)
299                 ;
300
301         writel(DPLL_CLKDCOLDO_GATE_CTRL, &cmwkup->clkdcoldodpllper);
302 }
303
304 static inline void per_pll_config(void)
305 {
306         per_pll_config_val(PERPLL_M);
307 }
308
309 static void disp_pll_config_val(int m)
310 {
311         u32 clkmode, clksel, div_m2;
312
313         clkmode = readl(&cmwkup->clkmoddplldisp);
314         clksel = readl(&cmwkup->clkseldplldisp);
315         div_m2 = readl(&cmwkup->divm2dplldisp);
316
317         /* Set the PLL to bypass Mode */
318         writel(PLL_BYPASS_MODE, &cmwkup->clkmoddplldisp);
319
320         while (!(readl(&cmwkup->idlestdplldisp) & ST_MN_BYPASS))
321                 ;
322
323         clksel &= ~CLK_SEL_MASK;
324         clksel |= (m << CLK_SEL_SHIFT) | DISPPLL_N;
325         writel(clksel, &cmwkup->clkseldplldisp);
326
327         div_m2 &= ~CLK_DIV2_MASK;
328         div_m2 |= DISPPLL_M2;
329         writel(div_m2, &cmwkup->divm2dplldisp);
330
331         clkmode &= ~CLK_MODE_MASK;
332         clkmode |= CLK_MODE_SEL;
333         writel(clkmode, &cmwkup->clkmoddplldisp);
334
335         while (!(readl(&cmwkup->idlestdplldisp) & ST_DPLL_CLK))
336                 ;
337 }
338
339 static inline void disp_pll_config(void)
340 {
341         disp_pll_config_val(DISPPLL_M);
342 }
343
344 void ddr_pll_config(unsigned int ddrpll_m)
345 {
346         u32 clkmode, clksel, div_m2;
347
348         clkmode = readl(&cmwkup->clkmoddpllddr);
349         clksel = readl(&cmwkup->clkseldpllddr);
350         div_m2 = readl(&cmwkup->divm2dpllddr);
351
352         /* Set the PLL to bypass Mode */
353         clkmode &= ~CLK_MODE_MASK;
354         clkmode |= PLL_BYPASS_MODE;
355         writel(clkmode, &cmwkup->clkmoddpllddr);
356
357         /* Wait till bypass mode is enabled */
358         while (!(readl(&cmwkup->idlestdpllddr) & ST_MN_BYPASS))
359                 ;
360
361         clksel &= ~CLK_SEL_MASK;
362         clksel |= (ddrpll_m << CLK_SEL_SHIFT) | DDRPLL_N;
363         writel(clksel, &cmwkup->clkseldpllddr);
364
365         div_m2 &= ~CLK_DIV_MASK;
366         div_m2 |= DDRPLL_M2;
367         writel(div_m2, &cmwkup->divm2dpllddr);
368
369         clkmode &= ~CLK_MODE_MASK;
370         clkmode |= CLK_MODE_SEL;
371         writel(clkmode, &cmwkup->clkmoddpllddr);
372
373         /* Wait till dpll is locked */
374         while ((readl(&cmwkup->idlestdpllddr) & ST_DPLL_CLK) != ST_DPLL_CLK)
375                 ;
376 }
377
378 #ifdef CONFIG_SPL_BUILD
379 void enable_emif_clocks(void)
380 {
381         /* Enable the  EMIF_FW Functional clock */
382         writel(PRCM_MOD_EN, &cmper->emiffwclkctrl);
383         /* Enable EMIF0 Clock */
384         writel(PRCM_MOD_EN, &cmper->emifclkctrl);
385         /* Poll if module is functional */
386         while ((readl(&cmper->emifclkctrl)) != PRCM_MOD_EN)
387                 ;
388 }
389
390 /*
391  * Configure the PLL/PRCM for necessary peripherals
392  */
393 void pll_init()
394 {
395         mpu_pll_config();
396         core_pll_config();
397         per_pll_config();
398         disp_pll_config();
399
400         /* Enable the required interconnect clocks */
401         enable_interface_clocks();
402
403         /* Power domain wake up transition */
404         power_domain_wkup_transition();
405
406         /* Enable the required peripherals */
407         enable_per_clocks();
408 }
409 #endif
410
411 #define M(mn) (((mn) & CLK_SEL_MASK) >> CLK_SEL_SHIFT)
412 #define N(mn) ((mn) & CLK_DIV2_MASK)
413
414 unsigned long __clk_get_rate(u32 m_n, u32 div_m2)
415 {
416         unsigned long rate;
417
418         div_m2 &= CLK_DIV_MASK;
419         debug("M=%u N=%u M2=%u\n", M(m_n), N(m_n), div_m2);
420         rate = V_OSCK / 1000 * M(m_n) / (N(m_n) + 1) / div_m2;
421         debug("CLK = %lu.%03luMHz\n", rate / 1000, rate % 1000);
422         return rate * 1000;
423 }
424
425 unsigned long lcdc_clk_rate(void)
426 {
427         return clk_get_rate(cmwkup, disp);
428 }
429
430 unsigned long mpu_clk_rate(void)
431 {
432         return clk_get_rate(cmwkup, mpu);
433 }
434
435 enum {
436         CLK_MPU_PLL,
437         CLK_CORE_PLL,
438         CLK_PER_PLL,
439         CLK_DISP_PLL,
440         CLK_GPMC,
441 };
442
443 static struct clk_lookup {
444         const char *name;
445         unsigned int index;
446 } am33xx_clk_lookup[] = {
447         { "mpu", CLK_MPU_PLL, },
448         { "core", CLK_CORE_PLL, },
449         { "per", CLK_PER_PLL, },
450         { "lcdc", CLK_DISP_PLL, },
451         { "gpmc", CLK_GPMC, },
452 };
453
454 #define print_pll(dom, pll) {                           \
455         u32 __pll = clk_get_rate(dom, pll);             \
456         printf("%-12s %4d.%03d MHz\n", #pll,            \
457                 __pll / 1000000, __pll / 1000 % 1000);  \
458         }
459
460 #define print_pll2(dom, n, pll) {                       \
461         u32 __m_n = readl(&(dom)->clkseldpll##pll);     \
462         u32 __div = readl(&(dom)->divm##n##dpll##pll);  \
463         u32 __pll = __clk_get_rate(__m_n, __div);       \
464         printf("%-12s %4d.%03d MHz\n", #pll "_m" #n,    \
465                 __pll / 1000000, __pll / 1000 % 1000);  \
466         }
467
468 static void do_showclocks(void)
469 {
470         print_pll(cmwkup, mpu);
471         print_pll2(cmwkup, 4, core);
472         print_pll2(cmwkup, 5, core);
473         print_pll2(cmwkup, 6, core);
474         print_pll(cmwkup, ddr);
475         print_pll(cmwkup, per);
476         print_pll(cmwkup, disp);
477 }
478
479 int do_clocks(cmd_tbl_t *cmdtp, int flag, int argc,
480         char *const argv[])
481 {
482         int i;
483         unsigned long freq;
484         unsigned long __attribute__((unused)) ref = ~0UL;
485
486         if (argc < 2) {
487                 do_showclocks();
488                 return CMD_RET_SUCCESS;
489         } else if (argc == 2 || argc > 4) {
490                 return CMD_RET_USAGE;
491         }
492
493         freq = simple_strtoul(argv[2], NULL, 0);
494         if (freq < 1000) {
495                 printf("Invalid clock frequency %lu\n", freq);
496                 return CMD_RET_FAILURE;
497         }
498         if (argc > 3) {
499                 ref = simple_strtoul(argv[3], NULL, 0);
500         }
501         for (i = 0; i < ARRAY_SIZE(am33xx_clk_lookup); i++) {
502                 if (strcasecmp(argv[1], am33xx_clk_lookup[i].name) == 0) {
503                         switch (am33xx_clk_lookup[i].index) {
504                         case CLK_MPU_PLL:
505                                 mpu_pll_config_val(freq / 1000000);
506                                 break;
507                         case CLK_CORE_PLL:
508                                 core_pll_config_val(freq / 1000000);
509                                 break;
510                         case CLK_PER_PLL:
511                                 per_pll_config_val(freq / 1000000);
512                                 break;
513                         case CLK_DISP_PLL:
514                                 disp_pll_config_val(freq / 1000000);
515                                 break;
516                         default:
517                                 printf("Cannot change %s clock\n",
518                                         am33xx_clk_lookup[i].name);
519                                 return CMD_RET_FAILURE;
520                         }
521
522                         printf("%s clock set to %lu.%03lu MHz\n",
523                                 am33xx_clk_lookup[i].name,
524                                 freq / 1000000, freq / 1000 % 1000);
525                         return CMD_RET_SUCCESS;
526                 }
527         }
528         if (i == ARRAY_SIZE(am33xx_clk_lookup)) {
529                 printf("clock %s not found; supported clocks are:\n", argv[1]);
530                 for (i = 0; i < ARRAY_SIZE(am33xx_clk_lookup); i++) {
531                         printf("\t%s\n", am33xx_clk_lookup[i].name);
532                 }
533         } else {
534                 printf("Failed to set clock %s to %s MHz\n",
535                         argv[1], argv[2]);
536         }
537         return CMD_RET_FAILURE;
538 }
539
540 U_BOOT_CMD(
541         clocks, 4, 0, do_clocks,
542         "display/set clocks",
543         "                    - display clock settings\n"
544         "clocks <clkname> <freq>    - set clock <clkname> to <freq> Hz"
545 );