1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun * clock_am33xx.c
3*4882a593Smuzhiyun *
4*4882a593Smuzhiyun * clocks for AM33XX based boards
5*4882a593Smuzhiyun *
6*4882a593Smuzhiyun * Copyright (C) 2013, Texas Instruments, Incorporated - http://www.ti.com/
7*4882a593Smuzhiyun *
8*4882a593Smuzhiyun * SPDX-License-Identifier: GPL-2.0+
9*4882a593Smuzhiyun */
10*4882a593Smuzhiyun
11*4882a593Smuzhiyun #include <common.h>
12*4882a593Smuzhiyun #include <asm/arch/cpu.h>
13*4882a593Smuzhiyun #include <asm/arch/sys_proto.h>
14*4882a593Smuzhiyun #include <asm/arch/clock.h>
15*4882a593Smuzhiyun #include <asm/arch/hardware.h>
16*4882a593Smuzhiyun #include <asm/io.h>
17*4882a593Smuzhiyun
18*4882a593Smuzhiyun #define OSC (V_OSCK/1000000)
19*4882a593Smuzhiyun
20*4882a593Smuzhiyun struct cm_perpll *const cmper = (struct cm_perpll *)CM_PER;
21*4882a593Smuzhiyun struct cm_wkuppll *const cmwkup = (struct cm_wkuppll *)CM_WKUP;
22*4882a593Smuzhiyun struct cm_dpll *const cmdpll = (struct cm_dpll *)CM_DPLL;
23*4882a593Smuzhiyun struct cm_rtc *const cmrtc = (struct cm_rtc *)CM_RTC;
24*4882a593Smuzhiyun
25*4882a593Smuzhiyun const struct dpll_regs dpll_mpu_regs = {
26*4882a593Smuzhiyun .cm_clkmode_dpll = CM_WKUP + 0x88,
27*4882a593Smuzhiyun .cm_idlest_dpll = CM_WKUP + 0x20,
28*4882a593Smuzhiyun .cm_clksel_dpll = CM_WKUP + 0x2C,
29*4882a593Smuzhiyun .cm_div_m2_dpll = CM_WKUP + 0xA8,
30*4882a593Smuzhiyun };
31*4882a593Smuzhiyun
32*4882a593Smuzhiyun const struct dpll_regs dpll_core_regs = {
33*4882a593Smuzhiyun .cm_clkmode_dpll = CM_WKUP + 0x90,
34*4882a593Smuzhiyun .cm_idlest_dpll = CM_WKUP + 0x5C,
35*4882a593Smuzhiyun .cm_clksel_dpll = CM_WKUP + 0x68,
36*4882a593Smuzhiyun .cm_div_m4_dpll = CM_WKUP + 0x80,
37*4882a593Smuzhiyun .cm_div_m5_dpll = CM_WKUP + 0x84,
38*4882a593Smuzhiyun .cm_div_m6_dpll = CM_WKUP + 0xD8,
39*4882a593Smuzhiyun };
40*4882a593Smuzhiyun
41*4882a593Smuzhiyun const struct dpll_regs dpll_per_regs = {
42*4882a593Smuzhiyun .cm_clkmode_dpll = CM_WKUP + 0x8C,
43*4882a593Smuzhiyun .cm_idlest_dpll = CM_WKUP + 0x70,
44*4882a593Smuzhiyun .cm_clksel_dpll = CM_WKUP + 0x9C,
45*4882a593Smuzhiyun .cm_div_m2_dpll = CM_WKUP + 0xAC,
46*4882a593Smuzhiyun };
47*4882a593Smuzhiyun
48*4882a593Smuzhiyun const struct dpll_regs dpll_ddr_regs = {
49*4882a593Smuzhiyun .cm_clkmode_dpll = CM_WKUP + 0x94,
50*4882a593Smuzhiyun .cm_idlest_dpll = CM_WKUP + 0x34,
51*4882a593Smuzhiyun .cm_clksel_dpll = CM_WKUP + 0x40,
52*4882a593Smuzhiyun .cm_div_m2_dpll = CM_WKUP + 0xA0,
53*4882a593Smuzhiyun };
54*4882a593Smuzhiyun
55*4882a593Smuzhiyun struct dpll_params dpll_mpu_opp100 = {
56*4882a593Smuzhiyun CONFIG_SYS_MPUCLK, OSC-1, 1, -1, -1, -1, -1};
57*4882a593Smuzhiyun const struct dpll_params dpll_core_opp100 = {
58*4882a593Smuzhiyun 1000, OSC-1, -1, -1, 10, 8, 4};
59*4882a593Smuzhiyun
60*4882a593Smuzhiyun const struct dpll_params dpll_mpu_opp[NUM_CRYSTAL_FREQ][NUM_OPPS] = {
61*4882a593Smuzhiyun { /* 19.2 MHz */
62*4882a593Smuzhiyun {125, 3, 2, -1, -1, -1, -1}, /* OPP 50 */
63*4882a593Smuzhiyun {-1, -1, -1, -1, -1, -1, -1}, /* OPP RESERVED */
64*4882a593Smuzhiyun {125, 3, 1, -1, -1, -1, -1}, /* OPP 100 */
65*4882a593Smuzhiyun {150, 3, 1, -1, -1, -1, -1}, /* OPP 120 */
66*4882a593Smuzhiyun {125, 2, 1, -1, -1, -1, -1}, /* OPP TB */
67*4882a593Smuzhiyun {625, 11, 1, -1, -1, -1, -1} /* OPP NT */
68*4882a593Smuzhiyun },
69*4882a593Smuzhiyun { /* 24 MHz */
70*4882a593Smuzhiyun {25, 0, 2, -1, -1, -1, -1}, /* OPP 50 */
71*4882a593Smuzhiyun {-1, -1, -1, -1, -1, -1, -1}, /* OPP RESERVED */
72*4882a593Smuzhiyun {25, 0, 1, -1, -1, -1, -1}, /* OPP 100 */
73*4882a593Smuzhiyun {30, 0, 1, -1, -1, -1, -1}, /* OPP 120 */
74*4882a593Smuzhiyun {100, 3, 1, -1, -1, -1, -1}, /* OPP TB */
75*4882a593Smuzhiyun {125, 2, 1, -1, -1, -1, -1} /* OPP NT */
76*4882a593Smuzhiyun },
77*4882a593Smuzhiyun { /* 25 MHz */
78*4882a593Smuzhiyun {24, 0, 2, -1, -1, -1, -1}, /* OPP 50 */
79*4882a593Smuzhiyun {-1, -1, -1, -1, -1, -1, -1}, /* OPP RESERVED */
80*4882a593Smuzhiyun {24, 0, 1, -1, -1, -1, -1}, /* OPP 100 */
81*4882a593Smuzhiyun {144, 4, 1, -1, -1, -1, -1}, /* OPP 120 */
82*4882a593Smuzhiyun {32, 0, 1, -1, -1, -1, -1}, /* OPP TB */
83*4882a593Smuzhiyun {40, 0, 1, -1, -1, -1, -1} /* OPP NT */
84*4882a593Smuzhiyun },
85*4882a593Smuzhiyun { /* 26 MHz */
86*4882a593Smuzhiyun {300, 12, 2, -1, -1, -1, -1}, /* OPP 50 */
87*4882a593Smuzhiyun {-1, -1, -1, -1, -1, -1, -1}, /* OPP RESERVED */
88*4882a593Smuzhiyun {300, 12, 1, -1, -1, -1, -1}, /* OPP 100 */
89*4882a593Smuzhiyun {360, 12, 1, -1, -1, -1, -1}, /* OPP 120 */
90*4882a593Smuzhiyun {400, 12, 1, -1, -1, -1, -1}, /* OPP TB */
91*4882a593Smuzhiyun {500, 12, 1, -1, -1, -1, -1} /* OPP NT */
92*4882a593Smuzhiyun },
93*4882a593Smuzhiyun };
94*4882a593Smuzhiyun
95*4882a593Smuzhiyun const struct dpll_params dpll_core_1000MHz[NUM_CRYSTAL_FREQ] = {
96*4882a593Smuzhiyun {625, 11, -1, -1, 10, 8, 4}, /* 19.2 MHz */
97*4882a593Smuzhiyun {125, 2, -1, -1, 10, 8, 4}, /* 24 MHz */
98*4882a593Smuzhiyun {40, 0, -1, -1, 10, 8, 4}, /* 25 MHz */
99*4882a593Smuzhiyun {500, 12, -1, -1, 10, 8, 4} /* 26 MHz */
100*4882a593Smuzhiyun };
101*4882a593Smuzhiyun
102*4882a593Smuzhiyun const struct dpll_params dpll_per_192MHz[NUM_CRYSTAL_FREQ] = {
103*4882a593Smuzhiyun {400, 7, 5, -1, -1, -1, -1}, /* 19.2 MHz */
104*4882a593Smuzhiyun {400, 9, 5, -1, -1, -1, -1}, /* 24 MHz */
105*4882a593Smuzhiyun {384, 9, 5, -1, -1, -1, -1}, /* 25 MHz */
106*4882a593Smuzhiyun {480, 12, 5, -1, -1, -1, -1} /* 26 MHz */
107*4882a593Smuzhiyun };
108*4882a593Smuzhiyun
109*4882a593Smuzhiyun const struct dpll_params dpll_ddr3_303MHz[NUM_CRYSTAL_FREQ] = {
110*4882a593Smuzhiyun {505, 15, 2, -1, -1, -1, -1}, /*19.2*/
111*4882a593Smuzhiyun {101, 3, 2, -1, -1, -1, -1}, /* 24 MHz */
112*4882a593Smuzhiyun {303, 24, 1, -1, 4, -1, -1}, /* 25 MHz */
113*4882a593Smuzhiyun {303, 12, 2, -1, 4, -1, -1} /* 26 MHz */
114*4882a593Smuzhiyun };
115*4882a593Smuzhiyun
116*4882a593Smuzhiyun const struct dpll_params dpll_ddr3_400MHz[NUM_CRYSTAL_FREQ] = {
117*4882a593Smuzhiyun {125, 5, 1, -1, -1, -1, -1}, /*19.2*/
118*4882a593Smuzhiyun {50, 2, 1, -1, -1, -1, -1}, /* 24 MHz */
119*4882a593Smuzhiyun {16, 0, 1, -1, 4, -1, -1}, /* 25 MHz */
120*4882a593Smuzhiyun {200, 12, 1, -1, 4, -1, -1} /* 26 MHz */
121*4882a593Smuzhiyun };
122*4882a593Smuzhiyun
123*4882a593Smuzhiyun const struct dpll_params dpll_ddr2_266MHz[NUM_CRYSTAL_FREQ] = {
124*4882a593Smuzhiyun {665, 47, 1, -1, -1, -1, -1}, /*19.2*/
125*4882a593Smuzhiyun {133, 11, 1, -1, -1, -1, -1}, /* 24 MHz */
126*4882a593Smuzhiyun {266, 24, 1, -1, 4, -1, -1}, /* 25 MHz */
127*4882a593Smuzhiyun {133, 12, 1, -1, 4, -1, -1} /* 26 MHz */
128*4882a593Smuzhiyun };
129*4882a593Smuzhiyun
get_dpll_mpu_params(void)130*4882a593Smuzhiyun __weak const struct dpll_params *get_dpll_mpu_params(void)
131*4882a593Smuzhiyun {
132*4882a593Smuzhiyun return &dpll_mpu_opp100;
133*4882a593Smuzhiyun }
134*4882a593Smuzhiyun
get_dpll_core_params(void)135*4882a593Smuzhiyun const struct dpll_params *get_dpll_core_params(void)
136*4882a593Smuzhiyun {
137*4882a593Smuzhiyun int ind = get_sys_clk_index();
138*4882a593Smuzhiyun
139*4882a593Smuzhiyun return &dpll_core_1000MHz[ind];
140*4882a593Smuzhiyun }
141*4882a593Smuzhiyun
get_dpll_per_params(void)142*4882a593Smuzhiyun const struct dpll_params *get_dpll_per_params(void)
143*4882a593Smuzhiyun {
144*4882a593Smuzhiyun int ind = get_sys_clk_index();
145*4882a593Smuzhiyun
146*4882a593Smuzhiyun return &dpll_per_192MHz[ind];
147*4882a593Smuzhiyun }
148*4882a593Smuzhiyun
setup_clocks_for_console(void)149*4882a593Smuzhiyun void setup_clocks_for_console(void)
150*4882a593Smuzhiyun {
151*4882a593Smuzhiyun clrsetbits_le32(&cmwkup->wkclkstctrl, CD_CLKCTRL_CLKTRCTRL_MASK,
152*4882a593Smuzhiyun CD_CLKCTRL_CLKTRCTRL_SW_WKUP <<
153*4882a593Smuzhiyun CD_CLKCTRL_CLKTRCTRL_SHIFT);
154*4882a593Smuzhiyun
155*4882a593Smuzhiyun clrsetbits_le32(&cmper->l4hsclkstctrl, CD_CLKCTRL_CLKTRCTRL_MASK,
156*4882a593Smuzhiyun CD_CLKCTRL_CLKTRCTRL_SW_WKUP <<
157*4882a593Smuzhiyun CD_CLKCTRL_CLKTRCTRL_SHIFT);
158*4882a593Smuzhiyun
159*4882a593Smuzhiyun clrsetbits_le32(&cmwkup->wkup_uart0ctrl,
160*4882a593Smuzhiyun MODULE_CLKCTRL_MODULEMODE_MASK,
161*4882a593Smuzhiyun MODULE_CLKCTRL_MODULEMODE_SW_EXPLICIT_EN <<
162*4882a593Smuzhiyun MODULE_CLKCTRL_MODULEMODE_SHIFT);
163*4882a593Smuzhiyun clrsetbits_le32(&cmper->uart1clkctrl,
164*4882a593Smuzhiyun MODULE_CLKCTRL_MODULEMODE_MASK,
165*4882a593Smuzhiyun MODULE_CLKCTRL_MODULEMODE_SW_EXPLICIT_EN <<
166*4882a593Smuzhiyun MODULE_CLKCTRL_MODULEMODE_SHIFT);
167*4882a593Smuzhiyun clrsetbits_le32(&cmper->uart2clkctrl,
168*4882a593Smuzhiyun MODULE_CLKCTRL_MODULEMODE_MASK,
169*4882a593Smuzhiyun MODULE_CLKCTRL_MODULEMODE_SW_EXPLICIT_EN <<
170*4882a593Smuzhiyun MODULE_CLKCTRL_MODULEMODE_SHIFT);
171*4882a593Smuzhiyun clrsetbits_le32(&cmper->uart3clkctrl,
172*4882a593Smuzhiyun MODULE_CLKCTRL_MODULEMODE_MASK,
173*4882a593Smuzhiyun MODULE_CLKCTRL_MODULEMODE_SW_EXPLICIT_EN <<
174*4882a593Smuzhiyun MODULE_CLKCTRL_MODULEMODE_SHIFT);
175*4882a593Smuzhiyun clrsetbits_le32(&cmper->uart4clkctrl,
176*4882a593Smuzhiyun MODULE_CLKCTRL_MODULEMODE_MASK,
177*4882a593Smuzhiyun MODULE_CLKCTRL_MODULEMODE_SW_EXPLICIT_EN <<
178*4882a593Smuzhiyun MODULE_CLKCTRL_MODULEMODE_SHIFT);
179*4882a593Smuzhiyun clrsetbits_le32(&cmper->uart5clkctrl,
180*4882a593Smuzhiyun MODULE_CLKCTRL_MODULEMODE_MASK,
181*4882a593Smuzhiyun MODULE_CLKCTRL_MODULEMODE_SW_EXPLICIT_EN <<
182*4882a593Smuzhiyun MODULE_CLKCTRL_MODULEMODE_SHIFT);
183*4882a593Smuzhiyun }
184*4882a593Smuzhiyun
enable_basic_clocks(void)185*4882a593Smuzhiyun void enable_basic_clocks(void)
186*4882a593Smuzhiyun {
187*4882a593Smuzhiyun u32 *const clk_domains[] = {
188*4882a593Smuzhiyun &cmper->l3clkstctrl,
189*4882a593Smuzhiyun &cmper->l4fwclkstctrl,
190*4882a593Smuzhiyun &cmper->l3sclkstctrl,
191*4882a593Smuzhiyun &cmper->l4lsclkstctrl,
192*4882a593Smuzhiyun &cmwkup->wkclkstctrl,
193*4882a593Smuzhiyun &cmper->emiffwclkctrl,
194*4882a593Smuzhiyun &cmrtc->clkstctrl,
195*4882a593Smuzhiyun 0
196*4882a593Smuzhiyun };
197*4882a593Smuzhiyun
198*4882a593Smuzhiyun u32 *const clk_modules_explicit_en[] = {
199*4882a593Smuzhiyun &cmper->l3clkctrl,
200*4882a593Smuzhiyun &cmper->l4lsclkctrl,
201*4882a593Smuzhiyun &cmper->l4fwclkctrl,
202*4882a593Smuzhiyun &cmwkup->wkl4wkclkctrl,
203*4882a593Smuzhiyun &cmper->l3instrclkctrl,
204*4882a593Smuzhiyun &cmper->l4hsclkctrl,
205*4882a593Smuzhiyun &cmwkup->wkgpio0clkctrl,
206*4882a593Smuzhiyun &cmwkup->wkctrlclkctrl,
207*4882a593Smuzhiyun &cmper->timer2clkctrl,
208*4882a593Smuzhiyun &cmper->gpmcclkctrl,
209*4882a593Smuzhiyun &cmper->elmclkctrl,
210*4882a593Smuzhiyun &cmper->mmc0clkctrl,
211*4882a593Smuzhiyun &cmper->mmc1clkctrl,
212*4882a593Smuzhiyun &cmwkup->wkup_i2c0ctrl,
213*4882a593Smuzhiyun &cmper->gpio1clkctrl,
214*4882a593Smuzhiyun &cmper->gpio2clkctrl,
215*4882a593Smuzhiyun &cmper->gpio3clkctrl,
216*4882a593Smuzhiyun &cmper->i2c1clkctrl,
217*4882a593Smuzhiyun &cmper->cpgmac0clkctrl,
218*4882a593Smuzhiyun &cmper->spi0clkctrl,
219*4882a593Smuzhiyun &cmrtc->rtcclkctrl,
220*4882a593Smuzhiyun &cmper->usb0clkctrl,
221*4882a593Smuzhiyun &cmper->emiffwclkctrl,
222*4882a593Smuzhiyun &cmper->emifclkctrl,
223*4882a593Smuzhiyun 0
224*4882a593Smuzhiyun };
225*4882a593Smuzhiyun
226*4882a593Smuzhiyun do_enable_clocks(clk_domains, clk_modules_explicit_en, 1);
227*4882a593Smuzhiyun
228*4882a593Smuzhiyun /* Select the Master osc 24 MHZ as Timer2 clock source */
229*4882a593Smuzhiyun writel(0x1, &cmdpll->clktimer2clk);
230*4882a593Smuzhiyun }
231*4882a593Smuzhiyun
232*4882a593Smuzhiyun /*
233*4882a593Smuzhiyun * Enable Spread Spectrum for the MPU by calculating the required
234*4882a593Smuzhiyun * values and setting the registers accordingly.
235*4882a593Smuzhiyun * @param permille The spreading in permille (10th of a percent)
236*4882a593Smuzhiyun */
set_mpu_spreadspectrum(int permille)237*4882a593Smuzhiyun void set_mpu_spreadspectrum(int permille)
238*4882a593Smuzhiyun {
239*4882a593Smuzhiyun u32 multiplier_m;
240*4882a593Smuzhiyun u32 predivider_n;
241*4882a593Smuzhiyun u32 cm_clksel_dpll_mpu;
242*4882a593Smuzhiyun u32 cm_clkmode_dpll_mpu;
243*4882a593Smuzhiyun u32 ref_clock;
244*4882a593Smuzhiyun u32 pll_bandwidth;
245*4882a593Smuzhiyun u32 mod_freq_divider;
246*4882a593Smuzhiyun u32 exponent;
247*4882a593Smuzhiyun u32 mantissa;
248*4882a593Smuzhiyun u32 delta_m_step;
249*4882a593Smuzhiyun
250*4882a593Smuzhiyun printf("Enabling Spread Spectrum of %d permille for MPU\n",
251*4882a593Smuzhiyun permille);
252*4882a593Smuzhiyun
253*4882a593Smuzhiyun /* Read PLL parameter m and n */
254*4882a593Smuzhiyun cm_clksel_dpll_mpu = readl(&cmwkup->clkseldpllmpu);
255*4882a593Smuzhiyun multiplier_m = (cm_clksel_dpll_mpu >> 8) & 0x3FF;
256*4882a593Smuzhiyun predivider_n = cm_clksel_dpll_mpu & 0x7F;
257*4882a593Smuzhiyun
258*4882a593Smuzhiyun /*
259*4882a593Smuzhiyun * Calculate reference clock (clock after pre-divider),
260*4882a593Smuzhiyun * its max. PLL bandwidth,
261*4882a593Smuzhiyun * and resulting mod_freq_divider
262*4882a593Smuzhiyun */
263*4882a593Smuzhiyun ref_clock = V_OSCK / (predivider_n + 1);
264*4882a593Smuzhiyun pll_bandwidth = ref_clock / 70;
265*4882a593Smuzhiyun mod_freq_divider = ref_clock / (4 * pll_bandwidth);
266*4882a593Smuzhiyun
267*4882a593Smuzhiyun /* Calculate Mantissa/Exponent */
268*4882a593Smuzhiyun exponent = 0;
269*4882a593Smuzhiyun mantissa = mod_freq_divider;
270*4882a593Smuzhiyun while ((mantissa > 127) && (exponent < 7)) {
271*4882a593Smuzhiyun exponent++;
272*4882a593Smuzhiyun mantissa /= 2;
273*4882a593Smuzhiyun }
274*4882a593Smuzhiyun if (mantissa > 127)
275*4882a593Smuzhiyun mantissa = 127;
276*4882a593Smuzhiyun
277*4882a593Smuzhiyun mod_freq_divider = mantissa << exponent;
278*4882a593Smuzhiyun
279*4882a593Smuzhiyun /*
280*4882a593Smuzhiyun * Calculate Modulation steps
281*4882a593Smuzhiyun * As we use Downspread only, the spread is twice the value of
282*4882a593Smuzhiyun * permille, so Div2!
283*4882a593Smuzhiyun * As it takes the value in percent, divide by ten!
284*4882a593Smuzhiyun */
285*4882a593Smuzhiyun delta_m_step = ((u32)((multiplier_m * permille) / 10 / 2)) << 18;
286*4882a593Smuzhiyun delta_m_step /= 100;
287*4882a593Smuzhiyun delta_m_step /= mod_freq_divider;
288*4882a593Smuzhiyun if (delta_m_step > 0xFFFFF)
289*4882a593Smuzhiyun delta_m_step = 0xFFFFF;
290*4882a593Smuzhiyun
291*4882a593Smuzhiyun /* Setup Spread Spectrum */
292*4882a593Smuzhiyun writel(delta_m_step, &cmwkup->sscdeltamstepdllmpu);
293*4882a593Smuzhiyun writel((exponent << 8) | mantissa, &cmwkup->sscmodfreqdivdpllmpu);
294*4882a593Smuzhiyun cm_clkmode_dpll_mpu = readl(&cmwkup->clkmoddpllmpu);
295*4882a593Smuzhiyun /* clear all SSC flags */
296*4882a593Smuzhiyun cm_clkmode_dpll_mpu &= ~(0xF << CM_CLKMODE_DPLL_SSC_EN_SHIFT);
297*4882a593Smuzhiyun /* enable SSC with Downspread only */
298*4882a593Smuzhiyun cm_clkmode_dpll_mpu |= CM_CLKMODE_DPLL_SSC_EN_MASK |
299*4882a593Smuzhiyun CM_CLKMODE_DPLL_SSC_DOWNSPREAD_MASK;
300*4882a593Smuzhiyun writel(cm_clkmode_dpll_mpu, &cmwkup->clkmoddpllmpu);
301*4882a593Smuzhiyun while (!(readl(&cmwkup->clkmoddpllmpu) & 0x2000))
302*4882a593Smuzhiyun ;
303*4882a593Smuzhiyun }
304