4 * clocks for AM33XX based boards
6 * Copyright (C) 2011, Texas Instruments, Incorporated - http://www.ti.com/
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.
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.
20 #include <asm/arch/cpu.h>
21 #include <asm/arch/clock.h>
22 #include <asm/arch/hardware.h>
25 #define PRCM_MOD_EN 0x2
26 #define PRCM_FORCE_WAKEUP 0x2
27 #define PRCM_FUNCTL 0x0
29 #define PRCM_EMIF_CLK_ACTIVITY BIT(2)
30 #define PRCM_L3_GCLK_ACTIVITY BIT(4)
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
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;
49 #ifdef CONFIG_SPL_BUILD
50 #define enable_clk(reg, val) __enable_clk(#reg, ®, val)
52 static void __enable_clk(const char *name, const void *reg, u32 mask)
54 unsigned long timeout = 10000000;
57 while (readl(reg) != mask)
58 /* poor man's timeout, since timers not initialized */
60 /* no error message, since console not yet available */
64 static void enable_interface_clocks(void)
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);
77 enable_clk(cmwkup->wkgpio0clkctrl, PRCM_MOD_EN);
81 * Force power domain wake up transition
82 * Ensure that the corresponding interface clock is active before
83 * using the peripheral
85 static void power_domain_wkup_transition(void)
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);
95 * Enable the peripheral clock for required peripherals
97 static void enable_per_clocks(void)
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);
106 #ifdef CONFIG_SYS_NS16550_COM1
108 enable_clk(cmwkup->wkup_uart0ctrl, PRCM_MOD_EN);
110 #ifdef CONFIG_SYS_NS16550_COM2
111 enable_clk(cmper->uart1clkctrl, PRCM_MOD_EN);
113 #ifdef CONFIG_SYS_NS16550_COM3
114 enable_clk(cmper->uart2clkctrl, PRCM_MOD_EN);
116 #ifdef CONFIG_SYS_NS16550_COM4
117 enable_clk(cmper->uart3clkctrl, PRCM_MOD_EN);
119 #ifdef CONFIG_SYS_NS16550_COM5
120 enable_clk(cmper->uart4clkctrl, PRCM_MOD_EN);
122 #ifdef CONFIG_SYS_NS16550_COM6
123 enable_clk(cmper->uart5clkctrl, PRCM_MOD_EN);
126 enable_clk(cmper->gpmcclkctrl, PRCM_MOD_EN);
129 enable_clk(cmper->elmclkctrl, PRCM_MOD_EN);
132 enable_clk(cmper->cpswclkstctrl, PRCM_MOD_EN);
133 enable_clk(cmper->cpgmac0clkctrl, PRCM_MOD_EN);
136 #ifndef CONFIG_OMAP_MMC_DEV_0
137 enable_clk(cmper->mmc0clkctrl, PRCM_MOD_EN);
139 #ifdef CONFIG_OMAP_MMC_DEV_1
140 enable_clk(cmper->mmc1clkctrl, PRCM_MOD_EN);
143 enable_clk(cmper->lcdclkctrl, PRCM_MOD_EN);
146 enable_clk(cmwkup->wkup_i2c0ctrl, PRCM_MOD_EN);
149 enable_clk(cmper->gpio1clkctrl, PRCM_MOD_EN);
150 enable_clk(cmper->gpio2clkctrl, PRCM_MOD_EN);
151 enable_clk(cmper->gpio3clkctrl, PRCM_MOD_EN);
154 enable_clk(cmper->i2c1clkctrl, PRCM_MOD_EN);
157 enable_clk(cmper->spi0clkctrl, PRCM_MOD_EN);
160 enable_clk(cmrtc->rtcclkctrl, PRCM_MOD_EN);
163 enable_clk(cmper->usb0clkctrl, PRCM_MOD_EN);
165 #endif /* CONFIG_SPL_BUILD */
167 void mpu_pll_config(int m)
169 u32 clkmode, clksel, div_m2;
171 clkmode = readl(&cmwkup->clkmoddpllmpu);
172 clksel = readl(&cmwkup->clkseldpllmpu);
173 div_m2 = readl(&cmwkup->divm2dpllmpu);
175 /* Set the PLL to bypass Mode */
176 writel(PLL_BYPASS_MODE, &cmwkup->clkmoddpllmpu);
177 while (readl(&cmwkup->idlestdpllmpu) != ST_MN_BYPASS)
180 clksel &= ~CLK_SEL_MASK;
181 clksel |= (m << CLK_SEL_SHIFT) | MPUPLL_N;
182 writel(clksel, &cmwkup->clkseldpllmpu);
184 div_m2 &= ~CLK_DIV_MASK;
186 writel(div_m2, &cmwkup->divm2dpllmpu);
188 clkmode &= ~CLK_MODE_MASK;
189 clkmode |= CLK_MODE_SEL;
190 writel(clkmode, &cmwkup->clkmoddpllmpu);
192 while (readl(&cmwkup->idlestdpllmpu) != ST_DPLL_CLK)
196 static void core_pll_config(int m)
198 u32 clkmode, clksel, div_m4, div_m5, div_m6;
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);
206 /* Set the PLL to bypass Mode */
207 writel(PLL_BYPASS_MODE, &cmwkup->clkmoddpllcore);
209 while (readl(&cmwkup->idlestdpllcore) != ST_MN_BYPASS)
212 clksel &= ~CLK_SEL_MASK;
213 clksel |= ((m << CLK_SEL_SHIFT) | COREPLL_N);
214 writel(clksel, &cmwkup->clkseldpllcore);
216 div_m4 &= ~CLK_DIV_MASK;
217 div_m4 |= COREPLL_M4;
218 writel(div_m4, &cmwkup->divm4dpllcore);
220 div_m5 &= ~CLK_DIV_MASK;
221 div_m5 |= COREPLL_M5;
222 writel(div_m5, &cmwkup->divm5dpllcore);
224 div_m6 &= ~CLK_DIV_MASK;
225 div_m6 |= COREPLL_M6;
226 writel(div_m6, &cmwkup->divm6dpllcore);
228 clkmode &= ~CLK_MODE_MASK;
229 clkmode |= CLK_MODE_SEL;
230 writel(clkmode, &cmwkup->clkmoddpllcore);
232 while (readl(&cmwkup->idlestdpllcore) != ST_DPLL_CLK)
236 static void per_pll_config(int m)
238 u32 clkmode, clksel, div_m2;
240 clkmode = readl(&cmwkup->clkmoddpllper);
241 clksel = readl(&cmwkup->clkseldpllper);
242 div_m2 = readl(&cmwkup->divm2dpllper);
244 /* Set the PLL to bypass Mode */
245 writel(PLL_BYPASS_MODE, &cmwkup->clkmoddpllper);
247 while (readl(&cmwkup->idlestdpllper) != ST_MN_BYPASS)
250 clksel &= ~CLK_SEL_MASK;
251 clksel |= (m << CLK_SEL_SHIFT) | PERPLL_N;
252 writel(clksel, &cmwkup->clkseldpllper);
254 div_m2 &= ~CLK_DIV2_MASK;
256 writel(div_m2, &cmwkup->divm2dpllper);
258 clkmode &= ~CLK_MODE_MASK;
259 clkmode |= CLK_MODE_SEL;
260 writel(clkmode, &cmwkup->clkmoddpllper);
262 while (readl(&cmwkup->idlestdpllper) != ST_DPLL_CLK)
265 writel(DPLL_CLKDCOLDO_GATE_CTRL, &cmwkup->clkdcoldodpllper);
268 static void disp_pll_config(int m)
270 u32 clkmode, clksel, div_m2;
272 clkmode = readl(&cmwkup->clkmoddplldisp);
273 clksel = readl(&cmwkup->clkseldplldisp);
274 div_m2 = readl(&cmwkup->divm2dplldisp);
276 /* Set the PLL to bypass Mode */
277 writel(PLL_BYPASS_MODE, &cmwkup->clkmoddplldisp);
279 while (!(readl(&cmwkup->idlestdplldisp) & ST_MN_BYPASS))
282 clksel &= ~CLK_SEL_MASK;
283 clksel |= (m << CLK_SEL_SHIFT) | DISPPLL_N;
284 writel(clksel, &cmwkup->clkseldplldisp);
286 div_m2 &= ~CLK_DIV2_MASK;
287 div_m2 |= DISPPLL_M2;
288 writel(div_m2, &cmwkup->divm2dplldisp);
290 clkmode &= ~CLK_MODE_MASK;
291 clkmode |= CLK_MODE_SEL;
292 writel(clkmode, &cmwkup->clkmoddplldisp);
294 while (!(readl(&cmwkup->idlestdplldisp) & ST_DPLL_CLK))
298 void ddr_pll_config(unsigned int ddrpll_m)
300 u32 clkmode, clksel, div_m2;
302 clkmode = readl(&cmwkup->clkmoddpllddr);
303 clksel = readl(&cmwkup->clkseldpllddr);
304 div_m2 = readl(&cmwkup->divm2dpllddr);
306 /* Set the PLL to bypass Mode */
307 clkmode &= ~CLK_MODE_MASK;
308 clkmode |= PLL_BYPASS_MODE;
309 writel(clkmode, &cmwkup->clkmoddpllddr);
311 /* Wait till bypass mode is enabled */
312 while (!(readl(&cmwkup->idlestdpllddr) & ST_MN_BYPASS))
315 clksel &= ~CLK_SEL_MASK;
316 clksel |= (ddrpll_m << CLK_SEL_SHIFT) | DDRPLL_N;
317 writel(clksel, &cmwkup->clkseldpllddr);
319 div_m2 &= ~CLK_DIV_MASK;
321 writel(div_m2, &cmwkup->divm2dpllddr);
323 clkmode &= ~CLK_MODE_MASK;
324 clkmode |= CLK_MODE_SEL;
325 writel(clkmode, &cmwkup->clkmoddpllddr);
327 /* Wait till dpll is locked */
328 while ((readl(&cmwkup->idlestdpllddr) & ST_DPLL_CLK) != ST_DPLL_CLK)
332 #ifdef CONFIG_SPL_BUILD
333 void enable_emif_clocks(void)
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)
345 * Configure the PLL/PRCM for necessary peripherals
349 mpu_pll_config(MPUPLL_M);
350 core_pll_config(COREPLL_M);
351 per_pll_config(PERPLL_M);
352 disp_pll_config(DISPPLL_M);
354 /* Enable the required interconnect clocks */
355 enable_interface_clocks();
357 /* Power domain wake up transition */
358 power_domain_wkup_transition();
360 /* Enable the required peripherals */
365 #define M(mn) (((mn) & CLK_SEL_MASK) >> CLK_SEL_SHIFT)
366 #define N(mn) ((mn) & CLK_DIV2_MASK)
368 unsigned long __clk_get_rate(u32 m_n, u32 div_m2)
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);
379 unsigned long lcdc_clk_rate(void)
381 return clk_get_rate(cmwkup, disp);
384 unsigned long mpu_clk_rate(void)
386 return clk_get_rate(cmwkup, mpu);
397 static struct clk_lookup {
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, },
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); \
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); \
422 static void do_showclocks(void)
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);
433 int do_clocks(cmd_tbl_t *cmdtp, int flag, int argc,
438 unsigned long __attribute__((unused)) ref = ~0UL;
442 return CMD_RET_SUCCESS;
443 } else if (argc == 2 || argc > 4) {
444 return CMD_RET_USAGE;
447 freq = simple_strtoul(argv[2], NULL, 0);
449 printf("Invalid clock frequency %lu\n", freq);
450 return CMD_RET_FAILURE;
453 ref = simple_strtoul(argv[3], NULL, 0);
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) {
459 mpu_pll_config(freq / 1000000);
462 core_pll_config(freq / 1000000);
465 per_pll_config(freq / 1000000);
468 disp_pll_config(freq / 1000000);
471 printf("Cannot change %s clock\n",
472 am33xx_clk_lookup[i].name);
473 return CMD_RET_FAILURE;
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;
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);
488 printf("Failed to set clock %s to %s MHz\n",
491 return CMD_RET_FAILURE;
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"