4 * clocks for AM33XX based boards
6 * Copyright (C) 2013, Texas Instruments, Incorporated - http://www.ti.com/
8 * SPDX-License-Identifier: GPL-2.0+
12 #include <asm/arch/cpu.h>
13 #include <asm/arch/clock.h>
14 #include <asm/arch/hardware.h>
17 #define PRCM_MOD_EN 0x2
18 #define PRCM_FORCE_WAKEUP 0x2
19 #define PRCM_FUNCTL 0x0
21 #define PRCM_EMIF_CLK_ACTIVITY BIT(2)
22 #define PRCM_L3_GCLK_ACTIVITY BIT(4)
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
36 #define OSC (V_OSCK/1000000)
38 #define MPUPLL_M CONFIG_SYS_MPUCLK
39 #define MPUPLL_N (OSC-1)
42 /* Core PLL Fdll = 1 GHZ, */
43 #define COREPLL_M 1000
44 #define COREPLL_N (OSC-1)
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 */
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
56 #define PERPLL_N (OSC-1)
59 /* DDR Freq is 266 MHZ for now */
60 /* Set Fdll = 400 MHZ , Fdll = M * 2 * CLKINP/ N + 1; clkout = Fdll /(2 * M2) */
62 #define DDRPLL_N (OSC-1)
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;
70 #ifdef CONFIG_SPL_BUILD
71 #define enable_clk(reg, val) __enable_clk(#reg, ®, val)
73 static void __enable_clk(const char *name, const void *reg, u32 mask)
75 unsigned long timeout = 10000000;
78 while (readl(reg) != mask)
79 /* poor man's timeout, since timers not initialized */
81 /* no error message, since console not yet available */
85 static void enable_interface_clocks(void)
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);
98 enable_clk(cmwkup->wkgpio0clkctrl, PRCM_MOD_EN);
102 * Force power domain wake up transition
103 * Ensure that the corresponding interface clock is active before
104 * using the peripheral
106 static void power_domain_wkup_transition(void)
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);
116 * Enable the peripheral clock for required peripherals
118 static void enable_per_clocks(void)
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);
127 #ifdef CONFIG_SYS_NS16550_COM1
129 enable_clk(cmwkup->wkup_uart0ctrl, PRCM_MOD_EN);
131 #ifdef CONFIG_SYS_NS16550_COM2
132 enable_clk(cmper->uart1clkctrl, PRCM_MOD_EN);
134 #ifdef CONFIG_SYS_NS16550_COM3
135 enable_clk(cmper->uart2clkctrl, PRCM_MOD_EN);
137 #ifdef CONFIG_SYS_NS16550_COM4
138 enable_clk(cmper->uart3clkctrl, PRCM_MOD_EN);
140 #ifdef CONFIG_SYS_NS16550_COM5
141 enable_clk(cmper->uart4clkctrl, PRCM_MOD_EN);
143 #ifdef CONFIG_SYS_NS16550_COM6
144 enable_clk(cmper->uart5clkctrl, PRCM_MOD_EN);
147 enable_clk(cmper->gpmcclkctrl, PRCM_MOD_EN);
150 enable_clk(cmper->elmclkctrl, PRCM_MOD_EN);
153 enable_clk(cmper->cpswclkstctrl, PRCM_MOD_EN);
154 enable_clk(cmper->cpgmac0clkctrl, PRCM_MOD_EN);
157 #ifndef CONFIG_OMAP_MMC_DEV_0
158 enable_clk(cmper->mmc0clkctrl, PRCM_MOD_EN);
160 #ifdef CONFIG_OMAP_MMC_DEV_1
161 enable_clk(cmper->mmc1clkctrl, PRCM_MOD_EN);
164 enable_clk(cmper->lcdclkctrl, PRCM_MOD_EN);
167 writel(PRCM_MOD_EN, &cmper->mmc1clkctrl);
168 while (readl(&cmper->mmc1clkctrl) != PRCM_MOD_EN)
172 enable_clk(cmwkup->wkup_i2c0ctrl, PRCM_MOD_EN);
175 enable_clk(cmper->gpio1clkctrl, PRCM_MOD_EN);
176 enable_clk(cmper->gpio2clkctrl, PRCM_MOD_EN);
177 enable_clk(cmper->gpio3clkctrl, PRCM_MOD_EN);
180 enable_clk(cmper->i2c1clkctrl, PRCM_MOD_EN);
183 enable_clk(cmper->spi0clkctrl, PRCM_MOD_EN);
186 enable_clk(cmrtc->rtcclkctrl, PRCM_MOD_EN);
189 enable_clk(cmper->usb0clkctrl, PRCM_MOD_EN);
191 #endif /* CONFIG_SPL_BUILD */
193 void mpu_pll_config_val(int mpull_m)
195 u32 clkmode, clksel, div_m2;
197 clkmode = readl(&cmwkup->clkmoddpllmpu);
198 clksel = readl(&cmwkup->clkseldpllmpu);
199 div_m2 = readl(&cmwkup->divm2dpllmpu);
201 /* Set the PLL to bypass Mode */
202 writel(PLL_BYPASS_MODE, &cmwkup->clkmoddpllmpu);
203 while (readl(&cmwkup->idlestdpllmpu) != ST_MN_BYPASS)
206 clksel &= ~CLK_SEL_MASK;
207 clksel |= (mpull_m << CLK_SEL_SHIFT) | MPUPLL_N;
208 writel(clksel, &cmwkup->clkseldpllmpu);
210 div_m2 &= ~CLK_DIV_MASK;
212 writel(div_m2, &cmwkup->divm2dpllmpu);
214 clkmode &= ~CLK_MODE_MASK;
215 clkmode |= CLK_MODE_SEL;
216 writel(clkmode, &cmwkup->clkmoddpllmpu);
218 while (readl(&cmwkup->idlestdpllmpu) != ST_DPLL_CLK)
222 void mpu_pll_config(void)
224 mpu_pll_config_val(CONFIG_SYS_MPUCLK);
227 static void core_pll_config_val(int m)
229 u32 clkmode, clksel, div_m4, div_m5, div_m6;
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);
237 /* Set the PLL to bypass Mode */
238 writel(PLL_BYPASS_MODE, &cmwkup->clkmoddpllcore);
240 while (readl(&cmwkup->idlestdpllcore) != ST_MN_BYPASS)
243 clksel &= ~CLK_SEL_MASK;
244 clksel |= ((m << CLK_SEL_SHIFT) | COREPLL_N);
245 writel(clksel, &cmwkup->clkseldpllcore);
247 div_m4 &= ~CLK_DIV_MASK;
248 div_m4 |= COREPLL_M4;
249 writel(div_m4, &cmwkup->divm4dpllcore);
251 div_m5 &= ~CLK_DIV_MASK;
252 div_m5 |= COREPLL_M5;
253 writel(div_m5, &cmwkup->divm5dpllcore);
255 div_m6 &= ~CLK_DIV_MASK;
256 div_m6 |= COREPLL_M6;
257 writel(div_m6, &cmwkup->divm6dpllcore);
259 clkmode &= ~CLK_MODE_MASK;
260 clkmode |= CLK_MODE_SEL;
261 writel(clkmode, &cmwkup->clkmoddpllcore);
263 while (readl(&cmwkup->idlestdpllcore) != ST_DPLL_CLK)
267 static inline void core_pll_config(void)
269 core_pll_config_val(COREPLL_M);
272 static void per_pll_config_val(int m)
274 u32 clkmode, clksel, div_m2;
276 clkmode = readl(&cmwkup->clkmoddpllper);
277 clksel = readl(&cmwkup->clkseldpllper);
278 div_m2 = readl(&cmwkup->divm2dpllper);
280 /* Set the PLL to bypass Mode */
281 writel(PLL_BYPASS_MODE, &cmwkup->clkmoddpllper);
283 while (readl(&cmwkup->idlestdpllper) != ST_MN_BYPASS)
286 clksel &= ~CLK_SEL_MASK;
287 clksel |= (m << CLK_SEL_SHIFT) | PERPLL_N;
288 writel(clksel, &cmwkup->clkseldpllper);
290 div_m2 &= ~CLK_DIV2_MASK;
292 writel(div_m2, &cmwkup->divm2dpllper);
294 clkmode &= ~CLK_MODE_MASK;
295 clkmode |= CLK_MODE_SEL;
296 writel(clkmode, &cmwkup->clkmoddpllper);
298 while (readl(&cmwkup->idlestdpllper) != ST_DPLL_CLK)
301 writel(DPLL_CLKDCOLDO_GATE_CTRL, &cmwkup->clkdcoldodpllper);
304 static inline void per_pll_config(void)
306 per_pll_config_val(PERPLL_M);
309 static void disp_pll_config_val(int m)
311 u32 clkmode, clksel, div_m2;
313 clkmode = readl(&cmwkup->clkmoddplldisp);
314 clksel = readl(&cmwkup->clkseldplldisp);
315 div_m2 = readl(&cmwkup->divm2dplldisp);
317 /* Set the PLL to bypass Mode */
318 writel(PLL_BYPASS_MODE, &cmwkup->clkmoddplldisp);
320 while (!(readl(&cmwkup->idlestdplldisp) & ST_MN_BYPASS))
323 clksel &= ~CLK_SEL_MASK;
324 clksel |= (m << CLK_SEL_SHIFT) | DISPPLL_N;
325 writel(clksel, &cmwkup->clkseldplldisp);
327 div_m2 &= ~CLK_DIV2_MASK;
328 div_m2 |= DISPPLL_M2;
329 writel(div_m2, &cmwkup->divm2dplldisp);
331 clkmode &= ~CLK_MODE_MASK;
332 clkmode |= CLK_MODE_SEL;
333 writel(clkmode, &cmwkup->clkmoddplldisp);
335 while (!(readl(&cmwkup->idlestdplldisp) & ST_DPLL_CLK))
339 static inline void disp_pll_config(void)
341 disp_pll_config_val(DISPPLL_M);
344 void ddr_pll_config(unsigned int ddrpll_m)
346 u32 clkmode, clksel, div_m2;
348 clkmode = readl(&cmwkup->clkmoddpllddr);
349 clksel = readl(&cmwkup->clkseldpllddr);
350 div_m2 = readl(&cmwkup->divm2dpllddr);
352 /* Set the PLL to bypass Mode */
353 clkmode &= ~CLK_MODE_MASK;
354 clkmode |= PLL_BYPASS_MODE;
355 writel(clkmode, &cmwkup->clkmoddpllddr);
357 /* Wait till bypass mode is enabled */
358 while (!(readl(&cmwkup->idlestdpllddr) & ST_MN_BYPASS))
361 clksel &= ~CLK_SEL_MASK;
362 clksel |= (ddrpll_m << CLK_SEL_SHIFT) | DDRPLL_N;
363 writel(clksel, &cmwkup->clkseldpllddr);
365 div_m2 &= ~CLK_DIV_MASK;
367 writel(div_m2, &cmwkup->divm2dpllddr);
369 clkmode &= ~CLK_MODE_MASK;
370 clkmode |= CLK_MODE_SEL;
371 writel(clkmode, &cmwkup->clkmoddpllddr);
373 /* Wait till dpll is locked */
374 while ((readl(&cmwkup->idlestdpllddr) & ST_DPLL_CLK) != ST_DPLL_CLK)
378 #ifdef CONFIG_SPL_BUILD
379 void enable_emif_clocks(void)
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)
391 * Configure the PLL/PRCM for necessary peripherals
400 /* Enable the required interconnect clocks */
401 enable_interface_clocks();
403 /* Power domain wake up transition */
404 power_domain_wkup_transition();
406 /* Enable the required peripherals */
411 #define M(mn) (((mn) & CLK_SEL_MASK) >> CLK_SEL_SHIFT)
412 #define N(mn) ((mn) & CLK_DIV2_MASK)
414 unsigned long __clk_get_rate(u32 m_n, u32 div_m2)
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);
425 unsigned long lcdc_clk_rate(void)
427 return clk_get_rate(cmwkup, disp);
430 unsigned long mpu_clk_rate(void)
432 return clk_get_rate(cmwkup, mpu);
443 static struct clk_lookup {
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, },
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); \
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); \
468 static void do_showclocks(void)
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);
479 int do_clocks(cmd_tbl_t *cmdtp, int flag, int argc,
484 unsigned long __attribute__((unused)) ref = ~0UL;
488 return CMD_RET_SUCCESS;
489 } else if (argc == 2 || argc > 4) {
490 return CMD_RET_USAGE;
493 freq = simple_strtoul(argv[2], NULL, 0);
495 printf("Invalid clock frequency %lu\n", freq);
496 return CMD_RET_FAILURE;
499 ref = simple_strtoul(argv[3], NULL, 0);
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) {
505 mpu_pll_config_val(freq / 1000000);
508 core_pll_config_val(freq / 1000000);
511 per_pll_config_val(freq / 1000000);
514 disp_pll_config_val(freq / 1000000);
517 printf("Cannot change %s clock\n",
518 am33xx_clk_lookup[i].name);
519 return CMD_RET_FAILURE;
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;
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);
534 printf("Failed to set clock %s to %s MHz\n",
537 return CMD_RET_FAILURE;
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"