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
35 #define OSC (V_OSCK/1000000)
37 #define MPUPLL_M CONFIG_SYS_MPUCLK
38 #define MPUPLL_N (OSC - 1)
41 /* Core PLL Fdll = 1 GHZ, */
42 #define COREPLL_M 1000
43 #define COREPLL_N (OSC - 1)
45 #define COREPLL_M4 10 /* CORE_CLKOUTM4 = 200 MHZ */
46 #define COREPLL_M5 8 /* CORE_CLKOUTM5 = 250 MHZ */
47 #define COREPLL_M6 4 /* CORE_CLKOUTM6 = 500 MHZ */
50 * USB PHY clock is 960 MHZ. Since, this comes directly from Fdll, Fdll
51 * frequency needs to be set to 960 MHZ. Hence,
52 * For clkout = 192 MHZ, Fdll = 960 MHZ, divider values are given below
55 #define PERPLL_N (OSC - 1)
58 /* DDR Freq is 266 MHZ for now */
59 /* Set Fdll = 400 MHZ , Fdll = M * 2 * CLKINP/ N + 1; clkout = Fdll /(2 * M2) */
61 #define DDRPLL_N (OSC - 1)
64 struct cm_perpll *const cmper = (struct cm_perpll *)CM_PER;
65 struct cm_wkuppll *const cmwkup = (struct cm_wkuppll *)CM_WKUP;
66 struct cm_dpll *const cmdpll = (struct cm_dpll *)CM_DPLL;
67 struct cm_rtc *const cmrtc = (struct cm_rtc *)CM_RTC;
69 const struct dpll_regs dpll_mpu_regs = {
70 .cm_clkmode_dpll = CM_WKUP + 0x88,
71 .cm_idlest_dpll = CM_WKUP + 0x20,
72 .cm_clksel_dpll = CM_WKUP + 0x2C,
73 .cm_div_m2_dpll = CM_WKUP + 0xA8,
76 const struct dpll_regs dpll_core_regs = {
77 .cm_clkmode_dpll = CM_WKUP + 0x90,
78 .cm_idlest_dpll = CM_WKUP + 0x5C,
79 .cm_clksel_dpll = CM_WKUP + 0x68,
80 .cm_div_m4_dpll = CM_WKUP + 0x80,
81 .cm_div_m5_dpll = CM_WKUP + 0x84,
82 .cm_div_m6_dpll = CM_WKUP + 0xD8,
85 const struct dpll_regs dpll_per_regs = {
86 .cm_clkmode_dpll = CM_WKUP + 0x8C,
87 .cm_idlest_dpll = CM_WKUP + 0x70,
88 .cm_clksel_dpll = CM_WKUP + 0x9C,
89 .cm_div_m2_dpll = CM_WKUP + 0xAC,
92 const struct dpll_regs dpll_ddr_regs = {
93 .cm_clkmode_dpll = CM_WKUP + 0x94,
94 .cm_idlest_dpll = CM_WKUP + 0x34,
95 .cm_clksel_dpll = CM_WKUP + 0x40,
96 .cm_div_m2_dpll = CM_WKUP + 0xA0,
99 struct dpll_params dpll_mpu_opp100 = {
100 CONFIG_SYS_MPUCLK, OSC-1, 1, -1, -1, -1, -1};
101 const struct dpll_params dpll_core_opp100 = {
102 1000, OSC-1, -1, -1, 10, 8, 4};
103 const struct dpll_params dpll_mpu = {
104 MPUPLL_M_300, OSC-1, 1, -1, -1, -1, -1};
105 const struct dpll_params dpll_core = {
106 50, OSC-1, -1, -1, 1, 1, 1};
107 const struct dpll_params dpll_per = {
108 960, OSC-1, 5, -1, -1, -1, -1};
110 const struct dpll_params *get_dpll_mpu_params(void)
115 const struct dpll_params *get_dpll_core_params(void)
120 const struct dpll_params *get_dpll_per_params(void)
125 void setup_clocks_for_console(void)
127 clrsetbits_le32(&cmwkup->wkclkstctrl, CD_CLKCTRL_CLKTRCTRL_MASK,
128 CD_CLKCTRL_CLKTRCTRL_SW_WKUP <<
129 CD_CLKCTRL_CLKTRCTRL_SHIFT);
131 clrsetbits_le32(&cmper->l4hsclkstctrl, CD_CLKCTRL_CLKTRCTRL_MASK,
132 CD_CLKCTRL_CLKTRCTRL_SW_WKUP <<
133 CD_CLKCTRL_CLKTRCTRL_SHIFT);
135 clrsetbits_le32(&cmwkup->wkup_uart0ctrl,
136 MODULE_CLKCTRL_MODULEMODE_MASK,
137 MODULE_CLKCTRL_MODULEMODE_SW_EXPLICIT_EN <<
138 MODULE_CLKCTRL_MODULEMODE_SHIFT);
139 clrsetbits_le32(&cmper->uart1clkctrl,
140 MODULE_CLKCTRL_MODULEMODE_MASK,
141 MODULE_CLKCTRL_MODULEMODE_SW_EXPLICIT_EN <<
142 MODULE_CLKCTRL_MODULEMODE_SHIFT);
143 clrsetbits_le32(&cmper->uart2clkctrl,
144 MODULE_CLKCTRL_MODULEMODE_MASK,
145 MODULE_CLKCTRL_MODULEMODE_SW_EXPLICIT_EN <<
146 MODULE_CLKCTRL_MODULEMODE_SHIFT);
147 clrsetbits_le32(&cmper->uart3clkctrl,
148 MODULE_CLKCTRL_MODULEMODE_MASK,
149 MODULE_CLKCTRL_MODULEMODE_SW_EXPLICIT_EN <<
150 MODULE_CLKCTRL_MODULEMODE_SHIFT);
151 clrsetbits_le32(&cmper->uart4clkctrl,
152 MODULE_CLKCTRL_MODULEMODE_MASK,
153 MODULE_CLKCTRL_MODULEMODE_SW_EXPLICIT_EN <<
154 MODULE_CLKCTRL_MODULEMODE_SHIFT);
155 clrsetbits_le32(&cmper->uart5clkctrl,
156 MODULE_CLKCTRL_MODULEMODE_MASK,
157 MODULE_CLKCTRL_MODULEMODE_SW_EXPLICIT_EN <<
158 MODULE_CLKCTRL_MODULEMODE_SHIFT);
161 void enable_basic_clocks(void)
163 u32 *const clk_domains[] = {
165 &cmper->l4fwclkstctrl,
166 &cmper->l3sclkstctrl,
167 &cmper->l4lsclkstctrl,
168 &cmwkup->wkclkstctrl,
169 &cmper->emiffwclkctrl,
174 u32 *const clk_modules_explicit_en[] = {
178 &cmwkup->wkl4wkclkctrl,
179 &cmper->l3instrclkctrl,
181 &cmwkup->wkgpio0clkctrl,
182 &cmwkup->wkctrlclkctrl,
183 &cmper->timer2clkctrl,
188 &cmwkup->wkup_i2c0ctrl,
189 &cmper->gpio1clkctrl,
190 &cmper->gpio2clkctrl,
191 &cmper->gpio3clkctrl,
193 &cmper->cpgmac0clkctrl,
197 &cmper->emiffwclkctrl,
202 do_enable_clocks(clk_domains, clk_modules_explicit_en, 1);
204 /* Select the Master osc 24 MHZ as Timer2 clock source */
205 writel(0x1, &cmdpll->clktimer2clk);
207 void mpu_pll_config_val(int mpull_m)
209 u32 clkmode, clksel, div_m2;
211 clkmode = readl(&cmwkup->clkmoddpllmpu);
212 clksel = readl(&cmwkup->clkseldpllmpu);
213 div_m2 = readl(&cmwkup->divm2dpllmpu);
215 /* Set the PLL to bypass Mode */
216 writel(PLL_BYPASS_MODE, &cmwkup->clkmoddpllmpu);
217 while (readl(&cmwkup->idlestdpllmpu) != ST_MN_BYPASS)
220 clksel &= ~CLK_SEL_MASK;
221 clksel |= (mpull_m << CLK_SEL_SHIFT) | MPUPLL_N;
222 writel(clksel, &cmwkup->clkseldpllmpu);
224 div_m2 &= ~CLK_DIV_MASK;
226 writel(div_m2, &cmwkup->divm2dpllmpu);
228 clkmode &= ~CLK_MODE_MASK;
229 clkmode |= CLK_MODE_SEL;
230 writel(clkmode, &cmwkup->clkmoddpllmpu);
232 while (readl(&cmwkup->idlestdpllmpu) != ST_DPLL_CLK)
236 void mpu_pll_config(void)
238 mpu_pll_config_val(CONFIG_SYS_MPUCLK);
241 static void core_pll_config_val(int m)
243 u32 clkmode, clksel, div_m4, div_m5, div_m6;
245 clkmode = readl(&cmwkup->clkmoddpllcore);
246 clksel = readl(&cmwkup->clkseldpllcore);
247 div_m4 = readl(&cmwkup->divm4dpllcore);
248 div_m5 = readl(&cmwkup->divm5dpllcore);
249 div_m6 = readl(&cmwkup->divm6dpllcore);
251 /* Set the PLL to bypass Mode */
252 writel(PLL_BYPASS_MODE, &cmwkup->clkmoddpllcore);
254 while (readl(&cmwkup->idlestdpllcore) != ST_MN_BYPASS)
257 clksel &= ~CLK_SEL_MASK;
258 clksel |= ((m << CLK_SEL_SHIFT) | COREPLL_N);
259 writel(clksel, &cmwkup->clkseldpllcore);
261 div_m4 &= ~CLK_DIV_MASK;
262 div_m4 |= COREPLL_M4;
263 writel(div_m4, &cmwkup->divm4dpllcore);
265 div_m5 &= ~CLK_DIV_MASK;
266 div_m5 |= COREPLL_M5;
267 writel(div_m5, &cmwkup->divm5dpllcore);
269 div_m6 &= ~CLK_DIV_MASK;
270 div_m6 |= COREPLL_M6;
271 writel(div_m6, &cmwkup->divm6dpllcore);
273 clkmode &= ~CLK_MODE_MASK;
274 clkmode |= CLK_MODE_SEL;
275 writel(clkmode, &cmwkup->clkmoddpllcore);
277 while (readl(&cmwkup->idlestdpllcore) != ST_DPLL_CLK)
281 static inline void core_pll_config(void)
283 core_pll_config_val(COREPLL_M);
286 static void per_pll_config_val(int m)
288 u32 clkmode, clksel, div_m2;
290 clkmode = readl(&cmwkup->clkmoddpllper);
291 clksel = readl(&cmwkup->clkseldpllper);
292 div_m2 = readl(&cmwkup->divm2dpllper);
294 /* Set the PLL to bypass Mode */
295 writel(PLL_BYPASS_MODE, &cmwkup->clkmoddpllper);
297 while (readl(&cmwkup->idlestdpllper) != ST_MN_BYPASS)
300 clksel &= ~CLK_SEL_MASK;
301 clksel |= (m << CLK_SEL_SHIFT) | PERPLL_N;
302 writel(clksel, &cmwkup->clkseldpllper);
304 div_m2 &= ~CLK_DIV2_MASK;
306 writel(div_m2, &cmwkup->divm2dpllper);
308 clkmode &= ~CLK_MODE_MASK;
309 clkmode |= CLK_MODE_SEL;
310 writel(clkmode, &cmwkup->clkmoddpllper);
312 while (readl(&cmwkup->idlestdpllper) != ST_DPLL_CLK)
315 writel(DPLL_CLKDCOLDO_GATE_CTRL, &cmwkup->clkdcoldodpllper);
318 static inline void per_pll_config(void)
320 per_pll_config_val(PERPLL_M);
323 static void disp_pll_config_val(int m)
325 u32 clkmode, clksel, div_m2;
327 clkmode = readl(&cmwkup->clkmoddplldisp);
328 clksel = readl(&cmwkup->clkseldplldisp);
329 div_m2 = readl(&cmwkup->divm2dplldisp);
331 /* Set the PLL to bypass Mode */
332 writel(PLL_BYPASS_MODE, &cmwkup->clkmoddplldisp);
334 while (!(readl(&cmwkup->idlestdplldisp) & ST_MN_BYPASS))
337 clksel &= ~CLK_SEL_MASK;
338 clksel |= (m << CLK_SEL_SHIFT) | DISPPLL_N;
339 writel(clksel, &cmwkup->clkseldplldisp);
341 div_m2 &= ~CLK_DIV2_MASK;
342 div_m2 |= DISPPLL_M2;
343 writel(div_m2, &cmwkup->divm2dplldisp);
345 clkmode &= ~CLK_MODE_MASK;
346 clkmode |= CLK_MODE_SEL;
347 writel(clkmode, &cmwkup->clkmoddplldisp);
349 while (!(readl(&cmwkup->idlestdplldisp) & ST_DPLL_CLK))
353 static inline void disp_pll_config(void)
355 disp_pll_config_val(DISPPLL_M);
358 void ddr_pll_config(unsigned int ddrpll_m)
360 u32 clkmode, clksel, div_m2;
362 clkmode = readl(&cmwkup->clkmoddpllddr);
363 clksel = readl(&cmwkup->clkseldpllddr);
364 div_m2 = readl(&cmwkup->divm2dpllddr);
366 /* Set the PLL to bypass Mode */
367 clkmode &= ~CLK_MODE_MASK;
368 clkmode |= PLL_BYPASS_MODE;
369 writel(clkmode, &cmwkup->clkmoddpllddr);
371 /* Wait till bypass mode is enabled */
372 while (!(readl(&cmwkup->idlestdpllddr) & ST_MN_BYPASS))
375 clksel &= ~CLK_SEL_MASK;
376 clksel |= (ddrpll_m << CLK_SEL_SHIFT) | DDRPLL_N;
377 writel(clksel, &cmwkup->clkseldpllddr);
379 div_m2 &= ~CLK_DIV_MASK;
381 writel(div_m2, &cmwkup->divm2dpllddr);
383 clkmode &= ~CLK_MODE_MASK;
384 clkmode |= CLK_MODE_SEL;
385 writel(clkmode, &cmwkup->clkmoddpllddr);
387 /* Wait till dpll is locked */
388 while ((readl(&cmwkup->idlestdpllddr) & ST_DPLL_CLK) != ST_DPLL_CLK)
392 #define M(mn) (((mn) & CLK_SEL_MASK) >> CLK_SEL_SHIFT)
393 #define N(mn) ((mn) & CLK_DIV2_MASK)
395 unsigned long __clk_get_rate(u32 m_n, u32 div_m2)
399 div_m2 &= CLK_DIV_MASK;
400 debug("M=%u N=%u M2=%u\n", M(m_n), N(m_n), div_m2);
401 rate = V_OSCK / 1000 * M(m_n) / (N(m_n) + 1) / div_m2;
402 debug("CLK = %lu.%03luMHz\n", rate / 1000, rate % 1000);
406 unsigned long lcdc_clk_rate(void)
408 return clk_get_rate(cmwkup, disp);
411 unsigned long mpu_clk_rate(void)
413 return clk_get_rate(cmwkup, mpu);
424 static struct clk_lookup {
427 } am33xx_clk_lookup[] = {
428 { "mpu", CLK_MPU_PLL, },
429 { "core", CLK_CORE_PLL, },
430 { "per", CLK_PER_PLL, },
431 { "lcdc", CLK_DISP_PLL, },
432 { "gpmc", CLK_GPMC, },
435 #define print_pll(dom, pll) { \
436 u32 __pll = clk_get_rate(dom, pll); \
437 printf("%-12s %4d.%03d MHz\n", #pll, \
438 __pll / 1000000, __pll / 1000 % 1000); \
441 #define print_pll2(dom, n, pll) { \
442 u32 __m_n = readl(&(dom)->clkseldpll##pll); \
443 u32 __div = readl(&(dom)->divm##n##dpll##pll); \
444 u32 __pll = __clk_get_rate(__m_n, __div); \
445 printf("%-12s %4d.%03d MHz\n", #pll "_m" #n, \
446 __pll / 1000000, __pll / 1000 % 1000); \
449 static void do_showclocks(void)
451 print_pll(cmwkup, mpu);
452 print_pll2(cmwkup, 4, core);
453 print_pll2(cmwkup, 5, core);
454 print_pll2(cmwkup, 6, core);
455 print_pll(cmwkup, ddr);
456 print_pll(cmwkup, per);
457 print_pll(cmwkup, disp);
460 int do_clocks(cmd_tbl_t *cmdtp, int flag, int argc,
465 unsigned long __attribute__((unused)) ref = ~0UL;
469 return CMD_RET_SUCCESS;
470 } else if (argc == 2 || argc > 4) {
471 return CMD_RET_USAGE;
474 freq = simple_strtoul(argv[2], NULL, 0);
476 printf("Invalid clock frequency %lu\n", freq);
477 return CMD_RET_FAILURE;
480 ref = simple_strtoul(argv[3], NULL, 0);
482 for (i = 0; i < ARRAY_SIZE(am33xx_clk_lookup); i++) {
483 if (strcasecmp(argv[1], am33xx_clk_lookup[i].name) == 0) {
484 switch (am33xx_clk_lookup[i].index) {
486 mpu_pll_config_val(freq / 1000000);
489 core_pll_config_val(freq / 1000000);
492 per_pll_config_val(freq / 1000000);
495 disp_pll_config_val(freq / 1000000);
498 printf("Cannot change %s clock\n",
499 am33xx_clk_lookup[i].name);
500 return CMD_RET_FAILURE;
503 printf("%s clock set to %lu.%03lu MHz\n",
504 am33xx_clk_lookup[i].name,
505 freq / 1000000, freq / 1000 % 1000);
506 return CMD_RET_SUCCESS;
509 if (i == ARRAY_SIZE(am33xx_clk_lookup)) {
510 printf("clock %s not found; supported clocks are:\n", argv[1]);
511 for (i = 0; i < ARRAY_SIZE(am33xx_clk_lookup); i++) {
512 printf("\t%s\n", am33xx_clk_lookup[i].name);
515 printf("Failed to set clock %s to %s MHz\n",
518 return CMD_RET_FAILURE;
522 clocks, 4, 0, do_clocks,
523 "display/set clocks",
524 " - display clock settings\n"
525 "clocks <clkname> <freq> - set clock <clkname> to <freq> Hz"