]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - cpu/arm_cortexa8/mx50/generic.c
applied patches from Freescale and Ka-Ro
[karo-tx-uboot.git] / cpu / arm_cortexa8 / mx50 / generic.c
1 /*
2  * Copyright (C) 2010 Freescale Semiconductor, Inc.
3  *
4  * See file CREDITS for list of people who contributed to this
5  * project.
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License as
9  * published by the Free Software Foundation; either version 2 of
10  * the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
20  * MA 02111-1307 USA
21  */
22
23 #include <common.h>
24 #include <asm/arch/mx50.h>
25 #include <asm/errno.h>
26 #include <asm/io.h>
27 #include "crm_regs.h"
28 #ifdef CONFIG_CMD_CLOCK
29 #include <asm/clock.h>
30 #endif
31 #include <div64.h>
32 #ifdef CONFIG_ARCH_CPU_INIT
33 #include <asm/cache-cp15.h>
34 #endif
35
36 enum pll_clocks {
37         PLL1_CLK = MXC_DPLL1_BASE,
38         PLL2_CLK = MXC_DPLL2_BASE,
39         PLL3_CLK = MXC_DPLL3_BASE,
40 };
41
42 enum pll_sw_clocks {
43         PLL1_SW_CLK,
44         PLL2_SW_CLK,
45         PLL3_SW_CLK,
46 };
47
48 #define AHB_CLK_ROOT 133333333
49 #define IPG_CLK_ROOT 66666666
50 #define IPG_PER_CLK_ROOT 40000000
51
52 #ifdef CONFIG_CMD_CLOCK
53 #define SZ_DEC_1M       1000000
54 #define PLL_PD_MAX      16      /* Actual pd+1 */
55 #define PLL_MFI_MAX     15
56 #define PLL_MFI_MIN     5
57 #define ARM_DIV_MAX     8
58 #define IPG_DIV_MAX     4
59 #define AHB_DIV_MAX     8
60 #define EMI_DIV_MAX     8
61 #define NFC_DIV_MAX     8
62
63 struct fixed_pll_mfd {
64     u32 ref_clk_hz;
65     u32 mfd;
66 };
67
68 const struct fixed_pll_mfd fixed_mfd[4] = {
69     {0,                   0},      /* reserved */
70     {0,                   0},      /* reserved */
71     {CONFIG_MX50_HCLK_FREQ, 24 * 16},    /* 384 */
72     {0,                   0},      /* reserved */
73 };
74
75 struct pll_param {
76     u32 pd;
77     u32 mfi;
78     u32 mfn;
79     u32 mfd;
80 };
81
82 #define PLL_FREQ_MAX(_ref_clk_) \
83                 (4 * _ref_clk_ * PLL_MFI_MAX)
84 #define PLL_FREQ_MIN(_ref_clk_) \
85                 ((2 * _ref_clk_ * (PLL_MFI_MIN - 1)) / PLL_PD_MAX)
86 #define MAX_DDR_CLK     420000000
87 #define AHB_CLK_MAX     133333333
88 #define IPG_CLK_MAX     (AHB_CLK_MAX / 2)
89 #define NFC_CLK_MAX     25000000
90 #define HSP_CLK_MAX     133333333
91 #endif
92
93 static u32 __decode_pll(enum pll_clocks pll, u32 infreq)
94 {
95         long mfi, mfn, mfd, pdf, ref_clk, mfn_abs;
96         unsigned long dp_op, dp_mfd, dp_mfn, dp_ctl, pll_hfsm, dbl;
97         s64 temp;
98
99         dp_ctl = __REG(pll + MXC_PLL_DP_CTL);
100         pll_hfsm = dp_ctl & MXC_PLL_DP_CTL_HFSM;
101         dbl = dp_ctl & MXC_PLL_DP_CTL_DPDCK0_2_EN;
102
103         if (pll_hfsm == 0) {
104                 dp_op = __REG(pll + MXC_PLL_DP_OP);
105                 dp_mfd = __REG(pll + MXC_PLL_DP_MFD);
106                 dp_mfn = __REG(pll + MXC_PLL_DP_MFN);
107         } else {
108                 dp_op = __REG(pll + MXC_PLL_DP_HFS_OP);
109                 dp_mfd = __REG(pll + MXC_PLL_DP_HFS_MFD);
110                 dp_mfn = __REG(pll + MXC_PLL_DP_HFS_MFN);
111         }
112         pdf = dp_op & MXC_PLL_DP_OP_PDF_MASK;
113         mfi = (dp_op & MXC_PLL_DP_OP_MFI_MASK) >> MXC_PLL_DP_OP_MFI_OFFSET;
114         mfi = (mfi <= 5) ? 5 : mfi;
115         mfd = dp_mfd & MXC_PLL_DP_MFD_MASK;
116         mfn = mfn_abs = dp_mfn & MXC_PLL_DP_MFN_MASK;
117         /* Sign extend to 32-bits */
118         if (mfn >= 0x04000000) {
119                 mfn |= 0xFC000000;
120                 mfn_abs = -mfn;
121         }
122
123         ref_clk = 2 * infreq;
124         if (dbl != 0)
125                 ref_clk *= 2;
126
127         ref_clk /= (pdf + 1);
128         temp = (u64) ref_clk * mfn_abs;
129         do_div(temp, mfd + 1);
130         if (mfn < 0)
131                 temp = -temp;
132         temp = (ref_clk * mfi) + temp;
133
134         return temp;
135 }
136
137 static u32 __get_mcu_main_clk(void)
138 {
139         u32 reg, freq;
140         reg = (__REG(MXC_CCM_CACRR) & MXC_CCM_CACRR_ARM_PODF_MASK) >>
141             MXC_CCM_CACRR_ARM_PODF_OFFSET;
142         freq = __decode_pll(PLL1_CLK, CONFIG_MX50_HCLK_FREQ);
143         return freq / (reg + 1);
144 }
145
146 /*
147  * This function returns the low power audio clock.
148  */
149 u32 __get_lp_apm(void)
150 {
151         u32 ret_val = 0;
152         u32 cbcmr = __REG(MXC_CCM_CBCMR);
153
154         if (((cbcmr >> MXC_CCM_CBCMR_LP_APM_SEL_OFFSET) & 0x1) == 0)
155                 ret_val = CONFIG_MX50_HCLK_FREQ;
156         else
157                 ret_val = ((32768 * 1024));
158
159         return ret_val;
160 }
161
162 static u32 __get_periph_clk(void)
163 {
164         u32 reg;
165         reg = __REG(MXC_CCM_CBCDR);
166
167         switch ((reg & MXC_CCM_CBCDR_PERIPH_CLK_SEL_MASK) >>
168                 MXC_CCM_CBCDR_PERIPH_CLK_SEL_OFFSET) {
169         case 0:
170                 return __decode_pll(PLL1_CLK, CONFIG_MX50_HCLK_FREQ);
171         case 1:
172                 return __decode_pll(PLL2_CLK, CONFIG_MX50_HCLK_FREQ);
173         case 2:
174                 return __decode_pll(PLL3_CLK, CONFIG_MX50_HCLK_FREQ);
175         default:
176                 return __get_lp_apm();
177         }
178 }
179
180 static u32 __get_ipg_clk(void)
181 {
182         u32 ahb_podf, ipg_podf;
183
184         ahb_podf = __REG(MXC_CCM_CBCDR);
185         ipg_podf = (ahb_podf & MXC_CCM_CBCDR_IPG_PODF_MASK) >>
186                         MXC_CCM_CBCDR_IPG_PODF_OFFSET;
187         ahb_podf = (ahb_podf & MXC_CCM_CBCDR_AHB_PODF_MASK) >>
188                         MXC_CCM_CBCDR_AHB_PODF_OFFSET;
189         return __get_periph_clk() / ((ahb_podf + 1) * (ipg_podf + 1));
190 }
191
192 static u32 __get_ipg_per_clk(void)
193 {
194         u32 pred1, pred2, podf, clk;
195         if (__REG(MXC_CCM_CBCMR) & MXC_CCM_CBCMR_PERCLK_IPG_CLK_SEL)
196                 return __get_ipg_clk();
197
198         clk = __REG(MXC_CCM_CBCMR) & MXC_CCM_CBCMR_PERCLK_LP_APM_CLK_SEL ?
199                 __get_lp_apm() : __get_periph_clk();
200
201         podf = __REG(MXC_CCM_CBCDR);
202         pred1 = (podf & MXC_CCM_CBCDR_PERCLK_PRED1_MASK) >>
203                 MXC_CCM_CBCDR_PERCLK_PRED1_OFFSET;
204         pred2 = (podf & MXC_CCM_CBCDR_PERCLK_PRED2_MASK) >>
205                 MXC_CCM_CBCDR_PERCLK_PRED2_OFFSET;
206         podf = (podf & MXC_CCM_CBCDR_PERCLK_PODF_MASK) >>
207                 MXC_CCM_CBCDR_PERCLK_PODF_OFFSET;
208
209         return clk / ((pred1 + 1) * (pred2 + 1) * (podf + 1));
210 }
211
212 static u32 __get_uart_clk(void)
213 {
214         u32 freq = 0, reg, pred, podf;
215         reg = __REG(MXC_CCM_CSCMR1);
216         switch ((reg & MXC_CCM_CSCMR1_UART_CLK_SEL_MASK) >>
217                 MXC_CCM_CSCMR1_UART_CLK_SEL_OFFSET) {
218         case 0x0:
219                 freq = __decode_pll(PLL1_CLK, CONFIG_MX50_HCLK_FREQ);
220                 break;
221         case 0x1:
222                 freq = __decode_pll(PLL2_CLK, CONFIG_MX50_HCLK_FREQ);
223                 break;
224         case 0x2:
225                 freq = __decode_pll(PLL3_CLK, CONFIG_MX50_HCLK_FREQ);
226                 break;
227         case 0x3:
228                 freq = __get_lp_apm();
229                 break;
230         default:
231                 break;
232         }
233
234         reg = __REG(MXC_CCM_CSCDR1);
235
236         pred = (reg & MXC_CCM_CSCDR1_UART_CLK_PRED_MASK) >>
237                 MXC_CCM_CSCDR1_UART_CLK_PRED_OFFSET;
238
239         podf = (reg & MXC_CCM_CSCDR1_UART_CLK_PODF_MASK) >>
240                 MXC_CCM_CSCDR1_UART_CLK_PODF_OFFSET;
241         freq /= (pred + 1) * (podf + 1);
242
243         return freq;
244 }
245
246
247 static u32 __get_cspi_clk(void)
248 {
249         u32 ret_val = 0, pdf, pre_pdf, clk_sel, div;
250         u32 cscmr1 = __REG(MXC_CCM_CSCMR1);
251         u32 cscdr2 = __REG(MXC_CCM_CSCDR2);
252
253         pre_pdf = (cscdr2 & MXC_CCM_CSCDR2_CSPI_CLK_PRED_MASK) \
254                         >> MXC_CCM_CSCDR2_CSPI_CLK_PRED_OFFSET;
255         pdf = (cscdr2 & MXC_CCM_CSCDR2_CSPI_CLK_PODF_MASK) \
256                         >> MXC_CCM_CSCDR2_CSPI_CLK_PODF_OFFSET;
257         clk_sel = (cscmr1 & MXC_CCM_CSCMR1_CSPI_CLK_SEL_MASK) \
258                         >> MXC_CCM_CSCMR1_CSPI_CLK_SEL_OFFSET;
259
260         div = (pre_pdf + 1) * (pdf + 1);
261
262         switch (clk_sel) {
263         case 0:
264                 ret_val = __decode_pll(PLL1_CLK, CONFIG_MX50_HCLK_FREQ) / div;
265                 break;
266         case 1:
267                 ret_val = __decode_pll(PLL2_CLK, CONFIG_MX50_HCLK_FREQ) / div;
268                 break;
269         case 2:
270                 ret_val = __decode_pll(PLL3_CLK, CONFIG_MX50_HCLK_FREQ) / div;
271                 break;
272         default:
273                 ret_val = __get_lp_apm() / div;
274                 break;
275         }
276
277         return ret_val;
278 }
279
280 static u32 __get_axi_a_clk(void)
281 {
282         u32 cbcdr =  __REG(MXC_CCM_CBCDR);
283         u32 pdf = (cbcdr & MXC_CCM_CBCDR_AXI_A_PODF_MASK) \
284                         >> MXC_CCM_CBCDR_AXI_A_PODF_OFFSET;
285
286         return  __get_periph_clk() / (pdf + 1);
287 }
288
289 static u32 __get_axi_b_clk(void)
290 {
291         u32 cbcdr =  __REG(MXC_CCM_CBCDR);
292         u32 pdf = (cbcdr & MXC_CCM_CBCDR_AXI_B_PODF_MASK) \
293                         >> MXC_CCM_CBCDR_AXI_B_PODF_OFFSET;
294
295         return  __get_periph_clk() / (pdf + 1);
296 }
297
298 static u32 __get_ahb_clk(void)
299 {
300         u32 cbcdr =  __REG(MXC_CCM_CBCDR);
301         u32 pdf = (cbcdr & MXC_CCM_CBCDR_AHB_PODF_MASK) \
302                         >> MXC_CCM_CBCDR_AHB_PODF_OFFSET;
303
304         return  __get_periph_clk() / (pdf + 1);
305 }
306
307
308 static u32 __get_emi_slow_clk(void)
309 {
310         u32 cbcdr =  __REG(MXC_CCM_CBCDR);
311         u32 emi_clk_sel = cbcdr & MXC_CCM_CBCDR_WEIM_CLK_SEL;
312         u32 pdf = (cbcdr & MXC_CCM_CBCDR_WEIM_PODF_MASK) \
313                         >> MXC_CCM_CBCDR_WEIM_PODF_OFFSET;
314
315         if (emi_clk_sel)
316                 return  __get_ahb_clk() / (pdf + 1);
317
318         return  __get_periph_clk() / (pdf + 1);
319 }
320
321 static u32 __get_sys_clk(void)
322 {
323         u32 ret_val = 0, clk, sys_pll_div;
324         u32 clkseq_bypass = __REG(MXC_CCM_CLKSEQ_BYPASS);
325
326         /* Fixme Not handle OSC and PFD1 mux */
327         if ((clkseq_bypass & MXC_CCM_CLKSEQ_BYPASS_SYS_CLK_1) &&
328             clkseq_bypass & MXC_CCM_CLKSEQ_BYPASS_SYS_CLK_0) {
329                 sys_pll_div = __REG(MXC_CCM_CLK_SYS) \
330                                 & MXC_CCM_CLK_SYS_DIV_PLL_MASK;
331                 clk = __decode_pll(PLL1_CLK, CONFIG_MX50_HCLK_FREQ);
332                 if (sys_pll_div)
333                         clk /= sys_pll_div;
334                 ret_val = clk;
335         } else if ((clkseq_bypass & MXC_CCM_CLKSEQ_BYPASS_SYS_CLK_0) == 0) {
336                 ret_val = CONFIG_MX50_HCLK_FREQ; /* OSC */
337         }  else {
338
339                 printf("Warning, Fixme Not handle PFD1 mux\n");
340         }
341
342         return ret_val;
343
344 }
345 static u32 __get_ddr_clk(void)
346 {
347         u32 ret_val = 0, clk, ddr_pll_div;
348         u32 clk_ddr = __REG(MXC_CCM_CLK_DDR);
349         u32 ddr_clk_sel = clk_ddr & MXC_CCM_CLK_DDR_DDR_PFD_SEL;
350
351         if (!ddr_clk_sel) {
352                 ddr_pll_div = clk_ddr & \
353                         MXC_CCM_CLK_DDR_DDR_DIV_PLL_MASK;
354                 clk = __decode_pll(PLL1_CLK, CONFIG_MX50_HCLK_FREQ);
355                 if (ddr_pll_div)
356                         clk /= ddr_pll_div;
357                 ret_val = clk;
358         } else {
359
360                 printf("Warning, Fixme Not handle PFD1 mux\n");
361         }
362
363         return ret_val;
364 }
365
366 #ifdef CONFIG_CMD_MMC
367 static u32 __get_esdhc1_clk(void)
368 {
369         u32 ret_val = 0, div, pre_pdf, pdf;
370         u32 cscmr1 = __REG(MXC_CCM_CSCMR1);
371         u32 cscdr1 = __REG(MXC_CCM_CSCDR1);
372         u32 esdh1_clk_sel;
373
374         esdh1_clk_sel = (cscmr1 & MXC_CCM_CSCMR1_ESDHC1_CLK_SEL_MASK) \
375                                 >> MXC_CCM_CSCMR1_ESDHC1_CLK_SEL_OFFSET;
376         pre_pdf = (cscdr1 & MXC_CCM_CSCDR1_ESDHC1_CLK_PRED_MASK) \
377                         >> MXC_CCM_CSCDR1_ESDHC1_CLK_PRED_OFFSET;
378         pdf = (cscdr1 & MXC_CCM_CSCDR1_ESDHC1_CLK_PODF_MASK) \
379                         >> MXC_CCM_CSCDR1_ESDHC1_CLK_PODF_OFFSET ;
380
381         div = (pre_pdf + 1) * (pdf + 1);
382
383         switch (esdh1_clk_sel) {
384         case 0:
385                 ret_val = __decode_pll(PLL1_CLK, CONFIG_MX50_HCLK_FREQ);
386                 break;
387         case 1:
388                 ret_val = __decode_pll(PLL2_CLK, CONFIG_MX50_HCLK_FREQ);
389                 break;
390         case 2:
391                 ret_val = __decode_pll(PLL3_CLK, CONFIG_MX50_HCLK_FREQ);
392                 break;
393         case 3:
394                 ret_val = __get_lp_apm();
395                 break;
396         default:
397                 break;
398         }
399
400         ret_val /= div;
401
402         return ret_val;
403 }
404
405 static u32 __get_esdhc3_clk(void)
406 {
407         u32 ret_val = 0, div, pre_pdf, pdf;
408         u32 esdh3_clk_sel;
409         u32 cscmr1 = __REG(MXC_CCM_CSCMR1);
410         u32 cscdr1 = __REG(MXC_CCM_CSCDR1);
411         esdh3_clk_sel = (cscmr1 & MXC_CCM_CSCMR1_ESDHC3_CLK_SEL_MASK) \
412                                 >> MXC_CCM_CSCMR1_ESDHC3_CLK_SEL_OFFSET;
413         pre_pdf = (cscdr1 & MXC_CCM_CSCDR1_ESDHC3_CLK_PRED_MASK) \
414                         >> MXC_CCM_CSCDR1_ESDHC3_CLK_PRED_OFFSET;
415         pdf = (cscdr1 & MXC_CCM_CSCDR1_ESDHC3_CLK_PODF_MASK) \
416                         >> MXC_CCM_CSCDR1_ESDHC3_CLK_PODF_OFFSET ;
417
418         div = (pre_pdf + 1) * (pdf + 1);
419
420         switch (esdh3_clk_sel) {
421         case 0:
422                 ret_val = __decode_pll(PLL1_CLK, CONFIG_MX50_HCLK_FREQ);
423                 break;
424         case 1:
425                 ret_val = __decode_pll(PLL2_CLK, CONFIG_MX50_HCLK_FREQ);
426                 break;
427         case 2:
428                 ret_val = __decode_pll(PLL3_CLK, CONFIG_MX50_HCLK_FREQ);
429                 break;
430         case 3:
431                 ret_val = __get_lp_apm();
432                 break;
433         case 5 ... 8:
434                 puts("Warning, Fixme,not handle PFD mux\n");
435
436                 break;
437         default:
438                 break;
439         }
440
441         ret_val /= div;
442
443         return ret_val;
444 }
445
446 static u32 __get_esdhc2_clk(void)
447 {
448         u32 cscmr1 = __REG(MXC_CCM_CSCMR1);
449         u32 esdh2_clk_sel = cscmr1 & MXC_CCM_CSCMR1_ESDHC2_CLK_SEL;
450         if (esdh2_clk_sel)
451                 return __get_esdhc3_clk();
452
453         return __get_esdhc1_clk();
454 }
455
456 static u32 __get_esdhc4_clk(void)
457 {
458         u32 cscmr1 = __REG(MXC_CCM_CSCMR1);
459         u32 esdh4_clk_sel = cscmr1 & MXC_CCM_CSCMR1_ESDHC4_CLK_SEL;
460         if (esdh4_clk_sel)
461                 return __get_esdhc3_clk();
462
463         return __get_esdhc1_clk();
464 }
465 #endif
466
467 unsigned int mxc_get_clock(enum mxc_clock clk)
468 {
469         switch (clk) {
470         case MXC_ARM_CLK:
471                 return __get_mcu_main_clk();
472         case MXC_PER_CLK:
473                 return __get_periph_clk();
474         case MXC_AHB_CLK:
475                 return __get_ahb_clk();
476         case MXC_IPG_CLK:
477                 return __get_ipg_clk();
478         case MXC_IPG_PERCLK:
479                 return __get_ipg_per_clk();
480         case MXC_UART_CLK:
481                 return __get_uart_clk();
482 #ifdef CONFIG_IMX_CSPI
483         case MXC_CSPI_CLK:
484                 return __get_cspi_clk();
485 #endif
486         case MXC_AXI_A_CLK:
487                 return __get_axi_a_clk();
488         case MXC_AXI_B_CLK:
489                 return __get_axi_b_clk();
490         case MXC_EMI_SLOW_CLK:
491                 return __get_emi_slow_clk();
492         case MXC_DDR_CLK:
493                 return __get_ddr_clk();
494 #ifdef CONFIG_CMD_MMC
495         case MXC_ESDHC_CLK:
496                 return __get_esdhc1_clk();
497         case MXC_ESDHC2_CLK:
498                 return __get_esdhc2_clk();
499         case MXC_ESDHC3_CLK:
500                 return __get_esdhc3_clk();
501         case MXC_ESDHC4_CLK:
502                 return __get_esdhc4_clk();
503 #endif
504         default:
505                 break;
506         }
507         return -1;
508 }
509
510 void mxc_dump_clocks(void)
511 {
512         u32 freq;
513         freq = __decode_pll(PLL1_CLK, CONFIG_MX50_HCLK_FREQ);
514         printf("mx50 pll1: %dMHz\n", freq / 1000000);
515         freq = __decode_pll(PLL2_CLK, CONFIG_MX50_HCLK_FREQ);
516         printf("mx50 pll2: %dMHz\n", freq / 1000000);
517         freq = __decode_pll(PLL3_CLK, CONFIG_MX50_HCLK_FREQ);
518         printf("mx50 pll3: %dMHz\n", freq / 1000000);
519         printf("ipg clock     : %dHz\n", mxc_get_clock(MXC_IPG_CLK));
520         printf("ipg per clock : %dHz\n", mxc_get_clock(MXC_IPG_PERCLK));
521         printf("uart clock    : %dHz\n", mxc_get_clock(MXC_UART_CLK));
522 #ifdef CONFIG_IMX_ECSPI
523         printf("cspi clock    : %dHz\n", mxc_get_clock(MXC_CSPI_CLK));
524 #endif
525         printf("ahb clock     : %dHz\n", mxc_get_clock(MXC_AHB_CLK));
526         printf("axi_a clock   : %dHz\n", mxc_get_clock(MXC_AXI_A_CLK));
527         printf("axi_b clock   : %dHz\n", mxc_get_clock(MXC_AXI_B_CLK));
528         printf("weim_clock    : %dHz\n", mxc_get_clock(MXC_EMI_SLOW_CLK));
529         printf("ddr clock     : %dHz\n", mxc_get_clock(MXC_DDR_CLK));
530 #ifdef CONFIG_CMD_MMC
531         printf("esdhc1 clock  : %dHz\n", mxc_get_clock(MXC_ESDHC_CLK));
532         printf("esdhc2 clock  : %dHz\n", mxc_get_clock(MXC_ESDHC2_CLK));
533         printf("esdhc3 clock  : %dHz\n", mxc_get_clock(MXC_ESDHC3_CLK));
534         printf("esdhc4 clock  : %dHz\n", mxc_get_clock(MXC_ESDHC4_CLK));
535 #endif
536 }
537
538 #ifdef CONFIG_CMD_CLOCK
539 /* precondition: m>0 and n>0.  Let g=gcd(m,n). */
540 static int gcd(int m, int n)
541 {
542         int t;
543         while (m > 0) {
544                 if (n > m) {
545                         t = m;
546                         m = n;
547                         n = t;
548                 } /* swap */
549                 m -= n;
550         }
551         return n;
552 }
553
554 /*!
555  * This is to calculate various parameters based on reference clock and
556  * targeted clock based on the equation:
557  *      t_clk = 2*ref_freq*(mfi + mfn/(mfd+1))/(pd+1)
558  * This calculation is based on a fixed MFD value for simplicity.
559  *
560  * @param ref       reference clock freq in Hz
561  * @param target    targeted clock in Hz
562  * @param pll           pll_param structure.
563  *
564  * @return          0 if successful; non-zero otherwise.
565  */
566 static int calc_pll_params(u32 ref, u32 target, struct pll_param *pll)
567 {
568         u64 pd, mfi = 1, mfn, mfd, t1;
569         u32 n_target = target;
570         u32 n_ref = ref, i;
571
572         /*
573          * Make sure targeted freq is in the valid range.
574          * Otherwise the following calculation might be wrong!!!
575          */
576         if (n_target < PLL_FREQ_MIN(ref) ||
577                 n_target > PLL_FREQ_MAX(ref)) {
578                 printf("Targeted peripheral clock should be"
579                         "within [%d - %d]\n",
580                         PLL_FREQ_MIN(ref) / SZ_DEC_1M,
581                         PLL_FREQ_MAX(ref) / SZ_DEC_1M);
582                 return -1;
583         }
584
585         for (i = 0; i < ARRAY_SIZE(fixed_mfd); i++) {
586                 if (fixed_mfd[i].ref_clk_hz == ref) {
587                         mfd = fixed_mfd[i].mfd;
588                         break;
589                 }
590         }
591
592         if (i == ARRAY_SIZE(fixed_mfd))
593                 return -1;
594
595         /* Use n_target and n_ref to avoid overflow */
596         for (pd = 1; pd <= PLL_PD_MAX; pd++) {
597                 t1 = n_target * pd;
598                 do_div(t1, (4 * n_ref));
599                 mfi = t1;
600                 if (mfi > PLL_MFI_MAX)
601                         return -1;
602                 else if (mfi < 5)
603                         continue;
604                 break;
605         }
606         /* Now got pd and mfi already */
607         /*
608         mfn = (((n_target * pd) / 4 - n_ref * mfi) * mfd) / n_ref;
609         */
610         t1 = n_target * pd;
611         do_div(t1, 4);
612         t1 -= n_ref * mfi;
613         t1 *= mfd;
614         do_div(t1, n_ref);
615         mfn = t1;
616 #ifdef CMD_CLOCK_DEBUG
617         printf("%d: ref=%d, target=%d, pd=%d,"
618                         "mfi=%d,mfn=%d, mfd=%d\n",
619                         __LINE__, ref, (u32)n_target,
620                         (u32)pd, (u32)mfi, (u32)mfn,
621                         (u32)mfd);
622 #endif
623         i = 1;
624         if (mfn != 0)
625                 i = gcd(mfd, mfn);
626         pll->pd = (u32)pd;
627         pll->mfi = (u32)mfi;
628         do_div(mfn, i);
629         pll->mfn = (u32)mfn;
630         do_div(mfd, i);
631         pll->mfd = (u32)mfd;
632
633         return 0;
634 }
635
636 int clk_info(u32 clk_type)
637 {
638         switch (clk_type) {
639         case CPU_CLK:
640                 printf("CPU Clock: %dHz\n",
641                         mxc_get_clock(MXC_ARM_CLK));
642                 break;
643         case PERIPH_CLK:
644                 printf("Peripheral Clock: %dHz\n",
645                         mxc_get_clock(MXC_PER_CLK));
646                 break;
647         case AHB_CLK:
648                 printf("AHB Clock: %dHz\n",
649                         mxc_get_clock(MXC_AHB_CLK));
650                 break;
651         case IPG_CLK:
652                 printf("IPG Clock: %dHz\n",
653                         mxc_get_clock(MXC_IPG_CLK));
654                 break;
655         case IPG_PERCLK:
656                 printf("IPG_PER Clock: %dHz\n",
657                         mxc_get_clock(MXC_IPG_PERCLK));
658                 break;
659         case UART_CLK:
660                 printf("UART Clock: %dHz\n",
661                         mxc_get_clock(MXC_UART_CLK));
662                 break;
663         case CSPI_CLK:
664                 printf("CSPI Clock: %dHz\n",
665                         mxc_get_clock(MXC_CSPI_CLK));
666                 break;
667         case DDR_CLK:
668                 printf("DDR Clock: %dHz\n",
669                         mxc_get_clock(MXC_DDR_CLK));
670                 break;
671         case ALL_CLK:
672                 printf("cpu clock: %dMHz\n",
673                         mxc_get_clock(MXC_ARM_CLK) / SZ_DEC_1M);
674                 mxc_dump_clocks();
675                 break;
676         default:
677                 printf("Unsupported clock type! :(\n");
678         }
679
680         return 0;
681 }
682
683 #define calc_div(target_clk, src_clk, limit) ({ \
684                 u32 tmp = 0;    \
685                 if ((src_clk % target_clk) <= 100)      \
686                         tmp = src_clk / target_clk;     \
687                 else    \
688                         tmp = (src_clk / target_clk) + 1;       \
689                 if (tmp > limit)        \
690                         tmp = limit;    \
691                 (tmp - 1);      \
692         })
693
694 u32 calc_per_cbcdr_val(u32 per_clk, u32 cbcmr)
695 {
696         u32 cbcdr = __REG(MXC_CCM_CBCDR);
697         u32 tmp_clk = 0, div = 0, clk_sel = 0;
698
699         cbcdr &= ~MXC_CCM_CBCDR_PERIPH_CLK_SEL;
700
701         /* emi_slow_podf divider */
702         tmp_clk = __get_emi_slow_clk();
703         clk_sel = cbcdr & MXC_CCM_CBCDR_EMI_CLK_SEL;
704         if (clk_sel) {
705                 div = calc_div(tmp_clk, per_clk, 8);
706                 cbcdr &= ~MXC_CCM_CBCDR_EMI_PODF_MASK;
707                 cbcdr |= (div << MXC_CCM_CBCDR_EMI_PODF_OFFSET);
708         }
709
710         /* axi_b_podf divider */
711         tmp_clk = __get_axi_b_clk();
712         div = calc_div(tmp_clk, per_clk, 8);
713         cbcdr &= ~MXC_CCM_CBCDR_AXI_B_PODF_MASK;
714         cbcdr |= (div << MXC_CCM_CBCDR_AXI_B_PODF_OFFSET);
715
716         /* axi_b_podf divider */
717         tmp_clk = __get_axi_a_clk();
718         div = calc_div(tmp_clk, per_clk, 8);
719         cbcdr &= ~MXC_CCM_CBCDR_AXI_A_PODF_MASK;
720         cbcdr |= (div << MXC_CCM_CBCDR_AXI_A_PODF_OFFSET);
721
722         /* ahb podf divider */
723         tmp_clk = AHB_CLK_ROOT;
724         div = calc_div(tmp_clk, per_clk, 8);
725         cbcdr &= ~MXC_CCM_CBCDR_AHB_PODF_MASK;
726         cbcdr |= (div << MXC_CCM_CBCDR_AHB_PODF_OFFSET);
727
728         return cbcdr;
729 }
730
731 #define CHANGE_PLL_SETTINGS(base, pd, mfi, mfn, mfd) \
732         {       \
733                 writel(0x1232, base + PLL_DP_CTL); \
734                 writel(0x2, base + PLL_DP_CONFIG);    \
735                 writel(((pd - 1) << 0) | (mfi << 4),    \
736                         base + PLL_DP_OP);      \
737                 writel(mfn, base + PLL_DP_MFN); \
738                 writel(mfd - 1, base + PLL_DP_MFD);     \
739                 writel(((pd - 1) << 0) | (mfi << 4),    \
740                         base + PLL_DP_HFS_OP);  \
741                 writel(mfn, base + PLL_DP_HFS_MFN);     \
742                 writel(mfd - 1, base + PLL_DP_HFS_MFD); \
743                 writel(0x1232, base + PLL_DP_CTL); \
744                 while (!readl(base + PLL_DP_CTL) & 0x1)  \
745                         ; \
746         }
747
748 int config_pll_clk(enum pll_clocks pll, struct pll_param *pll_param)
749 {
750         u32 ccsr = readl(CCM_BASE_ADDR + CLKCTL_CCSR);
751         u32 pll_base = pll;
752
753         switch (pll) {
754         case PLL1_CLK:
755                 /* Switch ARM to PLL2 clock */
756                 writel(ccsr | 0x4, CCM_BASE_ADDR + CLKCTL_CCSR);
757                 CHANGE_PLL_SETTINGS(pll_base, pll_param->pd,
758                                         pll_param->mfi, pll_param->mfn,
759                                         pll_param->mfd);
760                 /* Switch back */
761                 writel(ccsr & ~0x4, CCM_BASE_ADDR + CLKCTL_CCSR);
762                 break;
763         case PLL2_CLK:
764                 /* Switch to pll2 bypass clock */
765                 writel(ccsr | 0x2, CCM_BASE_ADDR + CLKCTL_CCSR);
766                 CHANGE_PLL_SETTINGS(pll_base, pll_param->pd,
767                                         pll_param->mfi, pll_param->mfn,
768                                         pll_param->mfd);
769                 /* Switch back */
770                 writel(ccsr & ~0x2, CCM_BASE_ADDR + CLKCTL_CCSR);
771                 break;
772         case PLL3_CLK:
773                 /* Switch to pll3 bypass clock */
774                 writel(ccsr | 0x1, CCM_BASE_ADDR + CLKCTL_CCSR);
775                 CHANGE_PLL_SETTINGS(pll_base, pll_param->pd,
776                                         pll_param->mfi, pll_param->mfn,
777                                         pll_param->mfd);
778                 /* Switch back */
779                 writel(ccsr & ~0x1, CCM_BASE_ADDR + CLKCTL_CCSR);
780                 break;
781         default:
782                 return -1;
783         }
784
785         return 0;
786 }
787
788 int config_core_clk(u32 ref, u32 freq)
789 {
790         int ret = 0;
791         u32 pll = 0;
792         struct pll_param pll_param;
793
794         memset(&pll_param, 0, sizeof(struct pll_param));
795
796         /* The case that periph uses PLL1 is not considered here */
797         pll = freq;
798         ret = calc_pll_params(ref, pll, &pll_param);
799         if (ret != 0) {
800                 printf("Can't find pll parameters: %d\n",
801                         ret);
802                 return ret;
803         }
804
805         return config_pll_clk(PLL1_CLK, &pll_param);
806 }
807
808 int config_periph_clk(u32 ref, u32 freq)
809 {
810         int ret = 0;
811         u32 pll = freq;
812         struct pll_param pll_param;
813
814         memset(&pll_param, 0, sizeof(struct pll_param));
815
816         if (__REG(MXC_CCM_CBCDR) & MXC_CCM_CBCDR_PERIPH_CLK_SEL) {
817                 /* Actually this case is not considered here */
818                 ret = calc_pll_params(ref, pll, &pll_param);
819                 if (ret != 0) {
820                         printf("Can't find pll parameters: %d\n",
821                                 ret);
822                         return ret;
823                 }
824                 switch ((__REG(MXC_CCM_CBCMR) & \
825                         MXC_CCM_CBCMR_PERIPH_CLK_SEL_MASK) >>
826                         MXC_CCM_CBCMR_PERIPH_CLK_SEL_OFFSET) {
827                 case 0:
828                         return config_pll_clk(PLL1_CLK, &pll_param);
829                         break;
830                 case 1:
831                         return config_pll_clk(PLL3_CLK, &pll_param);
832                         break;
833                 default:
834                         return -1;
835                 }
836         } else {
837                 u32 old_cbcmr = readl(CCM_BASE_ADDR + CLKCTL_CBCMR);
838                 u32 new_cbcdr = calc_per_cbcdr_val(pll, old_cbcmr);
839
840                 /* Switch peripheral to PLL3 */
841                 writel(0x00015154, CCM_BASE_ADDR + CLKCTL_CBCMR);
842                 writel(0x02888945, CCM_BASE_ADDR + CLKCTL_CBCDR);
843
844                 /* Make sure change is effective */
845                 while (readl(CCM_BASE_ADDR + CLKCTL_CDHIPR) != 0)
846                         ;
847
848                 /* Setup PLL2 */
849                 ret = calc_pll_params(ref, pll, &pll_param);
850                 if (ret != 0) {
851                         printf("Can't find pll parameters: %d\n",
852                                 ret);
853                         return ret;
854                 }
855                 config_pll_clk(PLL2_CLK, &pll_param);
856
857                 /* Switch peripheral back */
858                 writel(new_cbcdr, CCM_BASE_ADDR + CLKCTL_CBCDR);
859                 writel(old_cbcmr, CCM_BASE_ADDR + CLKCTL_CBCMR);
860
861                 /* Make sure change is effective */
862                 while (readl(CCM_BASE_ADDR + CLKCTL_CDHIPR) != 0)
863                         ;
864                 puts("\n");
865         }
866
867         return 0;
868 }
869
870 int config_ddr_clk(u32 emi_clk)
871 {
872         u32 clk_src;
873         s32 shift = 0, clk_sel, div = 1;
874         u32 cbcmr = readl(CCM_BASE_ADDR + CLKCTL_CBCMR);
875         u32 cbcdr = readl(CCM_BASE_ADDR + CLKCTL_CBCDR);
876
877         if (emi_clk > MAX_DDR_CLK) {
878                 printf("DDR clock should be less than"
879                         "%d MHz, assuming max value \n",
880                         (MAX_DDR_CLK / SZ_DEC_1M));
881                 emi_clk = MAX_DDR_CLK;
882         }
883
884         clk_src = __get_periph_clk();
885         /* Find DDR clock input */
886         clk_sel = (cbcmr >> 10) & 0x3;
887         switch (clk_sel) {
888         case 0:
889                 shift = 16;
890                 break;
891         case 1:
892                 shift = 19;
893                 break;
894         case 2:
895                 shift = 22;
896                 break;
897         case 3:
898                 shift = 10;
899                 break;
900         default:
901                 return -1;
902         }
903
904         if ((clk_src % emi_clk) == 0)
905                 div = clk_src / emi_clk;
906         else
907                 div = (clk_src / emi_clk) + 1;
908         if (div > 8)
909                 div = 8;
910
911         cbcdr = cbcdr & ~(0x7 << shift);
912         cbcdr |= ((div - 1) << shift);
913         writel(cbcdr, CCM_BASE_ADDR + CLKCTL_CBCDR);
914         while (readl(CCM_BASE_ADDR + CLKCTL_CDHIPR) != 0)
915                 ;
916         writel(0x0, CCM_BASE_ADDR + CLKCTL_CCDR);
917
918         return 0;
919 }
920
921 /*!
922  * This function assumes the expected core clock has to be changed by
923  * modifying the PLL. This is NOT true always but for most of the times,
924  * it is. So it assumes the PLL output freq is the same as the expected
925  * core clock (presc=1) unless the core clock is less than PLL_FREQ_MIN.
926  * In the latter case, it will try to increase the presc value until
927  * (presc*core_clk) is greater than PLL_FREQ_MIN. It then makes call to
928  * calc_pll_params() and obtains the values of PD, MFI,MFN, MFD based
929  * on the targeted PLL and reference input clock to the PLL. Lastly,
930  * it sets the register based on these values along with the dividers.
931  * Note 1) There is no value checking for the passed-in divider values
932  *         so the caller has to make sure those values are sensible.
933  *      2) Also adjust the NFC divider such that the NFC clock doesn't
934  *         exceed NFC_CLK_MAX.
935  *      3) IPU HSP clock is independent of AHB clock. Even it can go up to
936  *         177MHz for higher voltage, this function fixes the max to 133MHz.
937  *      4) This function should not have allowed diag_printf() calls since
938  *         the serial driver has been stoped. But leave then here to allow
939  *         easy debugging by NOT calling the cyg_hal_plf_serial_stop().
940  *
941  * @param ref       pll input reference clock (24MHz)
942  * @param freq          core clock in Hz
943  * @param clk_type  clock type, e.g CPU_CLK, DDR_CLK, etc.
944  * @return          0 if successful; non-zero otherwise
945  */
946 int clk_config(u32 ref, u32 freq, u32 clk_type)
947 {
948         freq *= SZ_DEC_1M;
949
950         switch (clk_type) {
951         case CPU_CLK:
952                 if (config_core_clk(ref, freq))
953                         return -1;
954                 break;
955         case PERIPH_CLK:
956                 if (config_periph_clk(ref, freq))
957                         return -1;
958                 break;
959         case DDR_CLK:
960                 if (config_ddr_clk(freq))
961                         return -1;
962                 break;
963         default:
964                 printf("Unsupported or invalid clock type! :(\n");
965         }
966
967         return 0;
968 }
969 #endif
970
971 #if defined(CONFIG_DISPLAY_CPUINFO)
972 int print_cpuinfo(void)
973 {
974         printf("CPU:   Freescale i.MX50 family %d.%dV at %d MHz\n",
975                (get_board_rev() & 0xFF) >> 4,
976                (get_board_rev() & 0xF),
977                 __get_mcu_main_clk() / 1000000);
978 #ifndef CONFIG_CMD_CLOCK
979                 mxc_dump_clocks();
980 #endif
981         return 0;
982 }
983 #endif
984
985 #if defined(CONFIG_MXC_FEC)
986 extern int mxc_fec_initialize(bd_t *bis);
987 extern void mxc_fec_set_mac_from_env(char *mac_addr);
988 #endif
989
990 int cpu_eth_init(bd_t *bis)
991 {
992         int rc = -ENODEV;
993 #if defined(CONFIG_MXC_FEC)
994         rc = mxc_fec_initialize(bis);
995 #endif
996         return rc;
997 }
998
999 #if defined(CONFIG_ARCH_CPU_INIT)
1000 int arch_cpu_init(void)
1001 {
1002         icache_enable();
1003         dcache_enable();
1004
1005 #ifdef CONFIG_L2_OFF
1006         l2_cache_disable();
1007 #else
1008         l2_cache_enable();
1009 #endif
1010         return 0;
1011 }
1012 #endif
1013