]> git.kernelconcepts.de Git - karo-tx-redboot.git/blob - packages/hal/arm/mx35/var/v2_0/src/cmds.c
Initial revision
[karo-tx-redboot.git] / packages / hal / arm / mx35 / var / v2_0 / src / cmds.c
1 //==========================================================================
2 //
3 //      cmds.c
4 //
5 //      SoC [platform] specific RedBoot commands
6 //
7 //==========================================================================
8 //####ECOSGPLCOPYRIGHTBEGIN####
9 // -------------------------------------------
10 // This file is part of eCos, the Embedded Configurable Operating System.
11 // Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
12 //
13 // eCos is free software; you can redistribute it and/or modify it under
14 // the terms of the GNU General Public License as published by the Free
15 // Software Foundation; either version 2 or (at your option) any later version.
16 //
17 // eCos is distributed in the hope that it will be useful, but WITHOUT ANY
18 // WARRANTY; without even the implied warranty of MERCHANTABILITY or
19 // FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
20 // for more details.
21 //
22 // You should have received a copy of the GNU General Public License along
23 // with eCos; if not, write to the Free Software Foundation, Inc.,
24 // 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
25 //
26 // As a special exception, if other files instantiate templates or use macros
27 // or inline functions from this file, or you compile this file and link it
28 // with other works to produce a work based on this file, this file does not
29 // by itself cause the resulting work to be covered by the GNU General Public
30 // License. However the source code for this file must still be made available
31 // in accordance with section (3) of the GNU General Public License.
32 //
33 // This exception does not invalidate any other reasons why a work based on
34 // this file might be covered by the GNU General Public License.
35 //
36 // Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
37 // at http://sources.redhat.com/ecos/ecos-license/
38 // -------------------------------------------
39 //####ECOSGPLCOPYRIGHTEND####
40 //==========================================================================
41 #include <redboot.h>
42 #include <cyg/hal/hal_intr.h>
43 #include <cyg/hal/plf_mmap.h>
44 #include <cyg/hal/hal_soc.h>         // Hardware definitions
45 #include <cyg/hal/hal_cache.h>
46
47 typedef unsigned long long  u64;
48 typedef unsigned int        u32;
49 typedef unsigned short      u16;
50 typedef unsigned char       u8;
51
52 #define SZ_DEC_1M       1000000
53 #define PLL_PD_MAX      16      //actual pd+1
54 #define PLL_MFI_MAX     15
55 #define PLL_MFI_MIN     5
56 #define PLL_MFD_MAX     1024    //actual mfd+1
57 #define PLL_MFN_MAX     511
58 #define NFC_PODF_MAX    16
59 #define PRESC_MAX       4
60
61 #define PLL_FREQ_MAX    (2 * PLL_REF_CLK * PLL_MFI_MAX)
62 #define PLL_FREQ_MIN    ((2 * PLL_REF_CLK * (PLL_MFI_MIN - 1)) / PLL_PD_MAX)
63 #define AHB_CLK_MAX     133333333
64 #define IPG_CLK_MAX     (AHB_CLK_MAX / 2)
65 #define NFC_CLK_MAX     25000000
66 // IPU-HSP clock is independent of the HCLK and can go up to 177MHz but requires
67 // higher voltage support. For simplicity, limit it to 133MHz
68 #define HSP_CLK_MAX     178000000
69
70 #define ERR_WRONG_CLK   -1
71 #define ERR_NO_MFI      -2
72 #define ERR_NO_MFN      -3
73 #define ERR_NO_PD       -4
74 #define ERR_NO_PRESC    -5
75 #define ERR_NO_AHB_DIV  -6
76
77 #define ARM_DIV_OFF     16
78 #define AHB_DIV_OFF     8
79 #define ARM_SEL_OFF     0
80
81 #define CLOCK_PATH_FIELD(arm, ahb, sel) \
82         (((arm) << ARM_DIV_OFF) + ((ahb) << AHB_DIV_OFF) + ((sel) << ARM_SEL_OFF))
83
84 static unsigned int clock_auto_path[8] =
85 {
86         CLOCK_PATH_FIELD(1, 3, 0), CLOCK_PATH_FIELD(1, 2, 1),
87         CLOCK_PATH_FIELD(2, 1, 1), -1,
88         CLOCK_PATH_FIELD(1, 6, 0), CLOCK_PATH_FIELD(1, 4, 1),
89         CLOCK_PATH_FIELD(2, 2, 1), -1,  
90 };
91
92 static unsigned int clock_consumer_path[16] =
93 {
94         CLOCK_PATH_FIELD(1, 4, 0), CLOCK_PATH_FIELD(1, 3, 1),
95         CLOCK_PATH_FIELD(2, 2, 0), -1,
96         -1, -1,
97         CLOCK_PATH_FIELD(4, 1, 0), CLOCK_PATH_FIELD(1, 5, 0),
98         CLOCK_PATH_FIELD(1, 8, 0), CLOCK_PATH_FIELD(1, 6, 1),
99         CLOCK_PATH_FIELD(2, 4, 0), -1,
100         -1, -1,
101         CLOCK_PATH_FIELD(4, 2, 0), -1,
102 };
103
104 static int hsp_div_table[3][16] =
105 {
106         {4, 3, 2, -1, -1, -1, 1, 5, 4, 3, 2, -1, -1, -1, 1, -1},
107         {-1, -1, -1, -1, -1, -1, -1, -1, 8, 6, 4, -1, -1, -1, 2, -1},
108         {3, -1, -1, -1, -1, -1, -1, -1, 3, -1, -1, -1, -1, -1, -1, -1},
109 };
110
111 u32 pll_clock(enum plls pll);
112 u32 get_main_clock(enum main_clocks clk);
113 u32 get_peri_clock(enum peri_clocks clk);
114
115 static u32 pll_mfd_fixed;
116
117 static void clock_setup(int argc, char *argv[]);
118 static void clko(int argc, char *argv[]);
119 extern unsigned int g_clock_src;
120 extern unsigned int system_rev;
121
122 RedBoot_cmd("clock",
123             "Setup/Display clock (max AHB=133MHz, max IPG=66.5MHz)\nSyntax:",
124             "[<ARM core clock in MHz> [:<ARM-AHB-IPG clock selection>[:<HSP selection>]]] \n\n\
125 If a selection is zero or no selectin is specified, the optimal divider values \n\
126 will be chosen. Examples:\n\
127    [clock]         -> Show various clocks\n\
128    [clock 532]     -> Core=532  AHB=133           IPG=66.5      HSP=133\n\
129    [clock 399]     -> Core=399  AHB=133           IPG=66.5      HSP=133\n\
130    [clock 532:?]   -> show ARM-AHB-IPG clock selections\n\
131    [clock 532:8]   -> Core=532  AHB=66.5          IPG=33.25     HSP=133\n\
132    [clock 532:8:?] -> show HSP selection\n\
133    [clock 532:8:2] -> Core=532  AHB=66.5          IPG=33.25     HSP=178\n",
134             clock_setup
135            );
136
137 static char consume_core_clocks[] = 
138           " selection of consumer path ARM clock source\n\
139           ========ARM\t AHB \t IPG ========\n\
140           <01> -  532\t 133 \t 66.5\n\
141           <02> -  399\t 133 \t 66.5\n\
142           <03> -  266\t 133 \t 66.5\n\
143           <07> -  133\t 133 \t 66.5\n\
144           <08> -  665\t 133 \t 66.5\n\
145           <09> -  532\t 66.5\t33.25\n\
146           <10> -  399\t 66.5\t33.25\n\
147           <11> -  266\t 66.5\t33.25\n\
148           <15> -  133\t 66.5\t33.25\n\
149            Other selection value can't be configured";
150
151 static char auto_core_clocks[] =
152           " selection of auto path ARM clock source\n\
153           ========ARM\t AHB \t IPG ========\n\
154           <1> -  399\t 133 \t 66.5\n\
155           <2> -  266\t 133 \t 66.5\n\
156           <3> -  133\t 133 \t 66.5\n\
157           <5> -  399\t 66.5\t33.25\n\
158           <6> -  266\t 66.5\t33.25\n\
159           <7> -  133\t 66.5\t33.25\n\
160            Other selection value can't be configured";
161
162 static char consume_hsp_clocks[] =
163           " selection of consumer path hsp clock source\n\
164           ========HSP ========\n\
165           <1> -  133\n\
166           <2> -  66.5\n\
167           <3> -  178\n\
168            Other selection value can't be configured";
169
170 static inline unsigned long decode_root_clocks(int mode, int pll, int index, int arm)
171 {
172         unsigned int * p, max, arm_div, ahb_div = 1;
173         if(mode) {
174                 p = clock_consumer_path;
175                 max = sizeof(clock_consumer_path)/sizeof(clock_consumer_path[0]);
176         } else {
177                 p = clock_auto_path;
178                 max = sizeof(clock_auto_path)/sizeof(clock_auto_path[0]);
179         }
180         if(index >= max || p[index] == -1) return 0;
181
182         arm_div = (p[index] >> 16)&0xFF;
183         if(!arm) {
184                 ahb_div = (p[index] >> 8)&0xFF;
185         }
186         if(!(p[index]&0xFF)) {
187                 return pll/(arm_div*ahb_div);
188         }
189         if(mode) {
190                 return (pll*3)/(arm_div*ahb_div*4);
191         }
192         return (pll*2)/(arm_div*ahb_div*3);
193 }
194
195 static inline unsigned long calc_pll_base_core(unsigned long core, unsigned int pdr0)
196 {
197         unsigned int * p, arm_div, index;
198         if(pdr0 & CLKMODE_CONSUMER) {
199                 p = clock_consumer_path;
200                 index = (pdr0 >> 16) & 0xF;
201         } else {
202                 p = clock_auto_path;
203                 index = (pdr0 >> 9) & 7;
204         }
205
206         arm_div = (p[index] >> 16)&0xFF;
207         if(!(p[index]&0xFF)) {
208                 return core*arm_div;
209         }
210         if(pdr0 & CLKMODE_CONSUMER) {
211                 return (core*arm_div*4)/3;
212         }
213         return (core*arm_div*3)/2;
214 }
215
216 static unsigned long get_arm_ahb_clock(int arm, unsigned long pdr0)
217 {
218         int mode = pdr0 & CLKMODE_CONSUMER, cfg;
219         unsigned long pll;
220         if(mode) {
221                 cfg = (pdr0 >> 16) & 0xF;
222         } else {
223                 cfg = (pdr0 >> 9) & 0x7;
224         }
225         pll = pll_clock(MCU_PLL);
226         return decode_root_clocks(mode, pll, cfg, arm);
227 }
228
229 /*!
230  * This is to calculate various parameters based on reference clock and
231  * targeted clock based on the equation:
232  *      t_clk = 2*ref_freq*(mfi + mfn/(mfd+1))/(pd+1)
233  * This calculation is based on a fixed MFD value for simplicity.
234  *
235  * @param ref       reference clock freq
236  * @param target    targeted clock in HZ
237  * @param p_pd      calculated pd value (pd value from register + 1) upon return
238  * @param p_mfi     calculated actual mfi value upon return
239  * @param p_mfn     calculated actual mfn value upon return
240  * @param p_mfd     fixed mfd value (mfd value from register + 1) upon return
241  *
242  * @return          0 if successful; non-zero otherwise.
243  */
244 int calc_pll_params(u32 ref, u32 target, u32 *p_pd,
245                     u32 *p_mfi, u32 *p_mfn, u32 *p_mfd)
246 {
247     u64 pd, mfi, mfn, n_target = (u64)target, n_ref = (u64)ref;
248
249     pll_mfd_fixed = 24 * 16;
250
251     // Make sure targeted freq is in the valid range. Otherwise the
252     // following calculation might be wrong!!!
253     if (target < PLL_FREQ_MIN || target > PLL_FREQ_MAX) {
254         return ERR_WRONG_CLK;
255     }
256     // Use n_target and n_ref to avoid overflow
257     for (pd = 1; pd <= PLL_PD_MAX; pd++) {
258         mfi = (n_target * pd) / (2 * n_ref);
259         if (mfi > PLL_MFI_MAX) {
260             return ERR_NO_MFI;
261         } else if (mfi < 5) {
262             continue;
263         }
264         break;
265     }
266     // Now got pd and mfi already
267     mfn = (((n_target * pd) / 2 - n_ref * mfi) * pll_mfd_fixed) / n_ref;
268     // Check mfn within limit and mfn < denominator
269     if (mfn > PLL_MFN_MAX || mfn >= pll_mfd_fixed) {
270         return ERR_NO_MFN;
271     }
272
273     if (pd > PLL_PD_MAX) {
274         return ERR_NO_PD;
275     }
276     *p_pd = (u32)pd;
277     *p_mfi = (u32)mfi;
278     *p_mfn = (u32)mfn;
279     *p_mfd = pll_mfd_fixed;
280     return 0;
281 }
282
283 /*!
284  * This function assumes the expected core clock has to be changed by
285  * modifying the PLL. This is NOT true always but for most of the times,
286  * it is. So it assumes the PLL output freq is the same as the expected
287  * core clock (presc=1) unless the core clock is less than PLL_FREQ_MIN.
288  * In the latter case, it will try to increase the presc value until
289  * (presc*core_clk) is greater than PLL_FREQ_MIN. It then makes call to
290  * calc_pll_params() and obtains the values of PD, MFI,MFN, MFD based
291  * on the targeted PLL and reference input clock to the PLL. Lastly,
292  * it sets the register based on these values along with the dividers.
293  * Note 1) There is no value checking for the passed-in divider values
294  *         so the caller has to make sure those values are sensible.
295  *      2) Also adjust the NFC divider such that the NFC clock doesn't
296  *         exceed NFC_CLK_MAX.
297  *      3) IPU HSP clock is independent of AHB clock. Even it can go up to
298  *         177MHz for higher voltage, this function fixes the max to 133MHz.
299  *      4) This function should not have allowed diag_printf() calls since
300  *         the serial driver has been stoped. But leave then here to allow
301  *         easy debugging by NOT calling the cyg_hal_plf_serial_stop().
302  *
303  * @param ref       pll input reference clock (32KHz or 26MHz)
304  * @param core_clk  core clock in Hz
305  * @param ahb_div   ahb divider to divide the core clock to get ahb clock
306  *                  (ahb_div - 1) needs to be set in the register
307  * @param ipg_div   ipg divider to divide the ahb clock to get ipg clock
308  *                  (ipg_div - 1) needs to be set in the register
309  # @return          0 if successful; non-zero otherwise
310  */
311 int configure_clock(u32 ref, u32 core_clk, u32 ahb_clk, u32 pdr0)
312 {
313     u32 pll, pd, mfi, mfn, mfd, brmo = 0, mpctl0;
314     u32 pdr4, nfc_div;
315     int ret, i;
316
317     pll = calc_pll_base_core(core_clk, pdr0);
318    
319     if((pll < PLL_FREQ_MIN ) || (pll > PLL_FREQ_MAX)) {
320             return ERR_WRONG_CLK;
321     }
322     // get nfc_div - make sure optimal NFC clock but less than NFC_CLK_MAX
323     for (nfc_div = 1; nfc_div <= NFC_PODF_MAX; nfc_div++) {
324         if ((ahb_clk/ nfc_div) <= NFC_CLK_MAX) {
325             break;
326         }
327     }
328
329     // pll is now the targeted pll output. Use it along with ref input clock
330     // to get pd, mfi, mfn, mfd
331     if ((ret = calc_pll_params(ref, pll, &pd, &mfi, &mfn, &mfd)) != 0) {
332         diag_printf("can't find pll(%d) parameters: %d\n", pll, ret);
333         return ret;
334     }
335 #ifdef CMD_CLOCK_DEBUG
336     diag_printf("ref=%d, pll=%d, pd=%d, mfi=%d,mfn=%d, mfd=%d\n",
337                 ref, pll, pd, mfi, mfn, mfd);
338 #endif
339
340     // blindly increase divider first to avoid too fast ahbclk and ipgclk
341     // in case the core clock increases too much
342     pdr4 = readl(CCM_BASE_ADDR + CLKCTL_PDR4);
343     pdr4 &= ~0xF0000000;
344     // increase the dividers. should work even when core clock is 832 (26*2*16)MHz
345     // which is unlikely true.
346     pdr4 |= (nfc_div -1) << 28;
347
348     // update PLL register
349     if ((mfd >= (10 * mfn)) || ((10 * mfn) >= (9 * mfd)))
350         brmo = 1;
351
352     mpctl0 = readl(CCM_BASE_ADDR + CLKCTL_MPCTL);
353     mpctl0 = (mpctl0 & 0x4000C000)  |
354              (brmo << 31)           |
355              ((pd - 1) << 26)       |
356              ((mfd - 1) << 16)      |
357              (mfi << 10)            |
358              mfn;
359     writel(mpctl0, CCM_BASE_ADDR + CLKCTL_MPCTL);
360     writel(pdr0, CCM_BASE_ADDR + CLKCTL_PDR0);
361     writel(pdr4, CCM_BASE_ADDR + CLKCTL_PDR4);
362     // add some delay for new values to take effect
363     for (i = 0; i < 10000; i++);
364     return 0;
365 }
366
367 static  int clock_setup_polling(u32 * params, u32 * ahb_clk, u32 * hsp_clk, u32 * pdr0)
368 {
369         u32 ahb_div, hsp_div;
370         diag_printf("data[0]=%d, data[1]=%d, data[2]=%d\n", params[0], params[1], params[2]);
371         if(!params[1]) {
372                 goto polling;
373         } else {
374                 if((*pdr0) & CLKMODE_CONSUMER) {
375                         if((params[1] > 16) || (clock_consumer_path[params[1] - 1] == -1)) {
376                                 diag_printf("Error: Invalid arm source selection in consumer path\n");
377                                 return -1;
378                         }
379                         ahb_div = (clock_consumer_path[params[1] - 1] >> AHB_DIV_OFF) & 0xFF;
380                 } else {
381                         if((params[1] > 8) || (clock_auto_path[params[1] -1 ] == -1)) {
382                                 diag_printf("Error: Invalid arm source selection in auto path\n");
383                                 return -1;
384                         }
385                         ahb_div = (clock_auto_path[params[1] - 1] >> AHB_DIV_OFF) & 0xFF;
386                 }
387         }
388         if(((*pdr0) & CLKMODE_CONSUMER)){
389                 if(!params[2]) params[2] = ((*pdr0 >> 20) & 0x3) + 1;
390                 if((params[2] > 3) || (hsp_div_table[params[2] - 1][params[1] -1] == -1)) {
391                         diag_printf("Error: current hsp source selection[%d] in current core path is invalid\n", params[2]);
392                         return -1;
393                 }
394         }
395   
396         if (params[0] < (PLL_FREQ_MIN / PRESC_MAX) || params[0] > PLL_FREQ_MAX) {
397                 diag_printf("Targeted core clock should be within [%d - %d]\n",
398                     PLL_FREQ_MIN / PRESC_MAX, PLL_FREQ_MAX);
399                 return -1;
400         }
401
402         if ((params[0] / ahb_div) > AHB_CLK_MAX) {
403                 diag_printf("Can't make AHB=%d since max=%d\n",
404                     params[0] / ahb_div, AHB_CLK_MAX);
405                 return -1;
406         }
407
408 //output:
409         *ahb_clk = params[0] / ahb_div;
410         if((*pdr0) & CLKMODE_CONSUMER) {
411                 *hsp_clk = params[0] /hsp_div_table[params[2] - 1][params[1] -1]; 
412                 *pdr0 &= ~((0x3<<20) | (0xF<<16));
413                 *pdr0 |= ((params[2] - 1)<< 20) | (params[1] -1) << 16;
414         } else {
415                 *hsp_clk = *ahb_clk; 
416                 *pdr0 &= ~(0x7 << 9);
417                 *pdr0 |= (params[1] -1) << 9;
418         }
419         return 0;
420 polling:
421         return -1;      
422         //goto output;
423 }
424
425 static void clock_setup(int argc,char *argv[])
426 {
427     int ret;
428     u32 pdr0 = readl(CCM_BASE_ADDR + CLKCTL_PDR0);
429     u32 i, data[3], temp, ahb_clk, hsp_clk;
430
431     if (system_rev & (0x2 << 4)) /* consumer path only in TO2.0 */
432             pdr0 |= 0x1;
433
434     if (argc == 1)
435         goto print_clock;
436    
437     memset(data, 0, sizeof(u32)*3); 
438     for (i = 0;  i < 3;  i++) {
439         if (!parse_num(*(&argv[1]), (unsigned long *)&temp, &argv[1], ":")) {
440             if(*argv[1] == '?') {
441                 switch(i) {
442                 case 1:
443                         diag_printf("ARM-AHB-IPG clock selections:\n");
444                         if(pdr0 & CLKMODE_CONSUMER) {
445                                 diag_printf("%s\n", consume_core_clocks);
446                         } else {  
447                                 diag_printf("%s\n", auto_core_clocks);
448                         } 
449                         return;
450                 case 2:
451                         diag_printf("HSP clock selections:\n");
452                         if(pdr0 & CLKMODE_CONSUMER) {
453                                 diag_printf("%s\n", consume_hsp_clocks);
454                         } else { 
455                                 diag_printf("In auto path, HSP clock always is same as AHB clock.\n");
456                         }
457                         return;
458                 }
459             }
460             diag_printf("Error: Invalid parameter\n");
461             return;
462         }
463         data[i] = temp;
464     }
465
466     data[0] = data[0] * SZ_DEC_1M;
467         
468     if(clock_setup_polling(data, &ahb_clk, &hsp_clk, &pdr0)) return;
469     diag_printf("Trying to set core=%d ahb=%d ipg=%d hsp=%d...\n",
470                 data[0], ahb_clk, ahb_clk/2, hsp_clk);
471     diag_printf("Current pdr0=%x\n", pdr0);
472     // stop the serial to be ready to adjust the clock
473     hal_delay_us(100000);
474     cyg_hal_plf_serial_stop();
475     // adjust the clock
476     ret = configure_clock(PLL_REF_CLK, data[0], ahb_clk, pdr0);
477     // restart the serial driver
478     cyg_hal_plf_serial_init();
479     hal_delay_us(100000);
480
481     if (ret != 0) {
482         diag_printf("Failed to setup clock: %d\n", ret);
483         return;
484     }
485     diag_printf("\n<<<New clock setting>>>\n");
486     // Now printing clocks
487 print_clock:
488     diag_printf("\nMPLL\t\tPPLL\n");
489     diag_printf("========================================\n");
490     diag_printf("%-16d%-16d\n\n", pll_clock(MCU_PLL), pll_clock(PER_PLL));
491     diag_printf("CPU\t\tAHB\t\tIPG\t\tIPG_PER\n");
492     diag_printf("========================================================\n");
493     diag_printf("%-16d%-16d%-16d%-16d\n\n",
494                 get_main_clock(CPU_CLK),
495                 get_main_clock(AHB_CLK),
496                 get_main_clock(IPG_CLK),
497                 get_main_clock(IPG_PER_CLK));
498
499     diag_printf("NFC\t\tUSB\t\tIPU-HSP\n");
500     diag_printf("========================================\n");
501     diag_printf("%-16d%-16d%-16d\n\n",
502                 get_main_clock(NFC_CLK),
503                 get_main_clock(USB_CLK),
504                 get_main_clock(HSP_CLK));
505
506     diag_printf("UART1-3\t\tSSI1\t\tSSI2\t\tCSI\n");
507     diag_printf("===========================================");
508     diag_printf("=============\n");
509
510     diag_printf("%-16d%-16d%-16d%-16d\n\n",
511                 get_peri_clock(UART1_BAUD),
512                 get_peri_clock(SSI1_BAUD),
513                 get_peri_clock(SSI2_BAUD),
514                 get_peri_clock(CSI_BAUD));
515
516     diag_printf("MSHC\t\tESDHC1\t\tESDHC2\t\tESDHC3\n");
517     diag_printf("===========================================");
518     diag_printf("=============\n");
519
520     diag_printf("%-16d%-16d%-16d%-16d\n\n",
521                 get_peri_clock(MSHC_CLK),
522                 get_peri_clock(ESDHC1_CLK),
523                 get_peri_clock(ESDHC2_CLK),
524                 get_peri_clock(ESDHC3_CLK));
525     
526     diag_printf("SPDIF\t\t\n");
527     diag_printf("===========================================");
528     diag_printf("=============\n");
529
530     diag_printf("%-16d\n\n",
531                 get_peri_clock(SPDIF_CLK));
532     diag_printf("IPG_PERCLK as baud clock for: UART1-5, I2C, SIM, OWIRE");
533     if (((readl(EPIT1_BASE_ADDR) >> 24) & 0x3) == 0x2) {
534         diag_printf(", EPIT");
535     }
536     if (((readl(GPT1_BASE_ADDR) >> 6) & 0x7) == 0x2) {
537         diag_printf("GPT,");
538     }
539     if (((readl(PWM_BASE_ADDR) >> 16) & 0x3) == 0x2) {
540         diag_printf("PWM,");
541     }
542     diag_printf("\n");
543 }
544
545 /*!
546  * This function returns the PLL output value in Hz based on pll.
547  */
548 u32 pll_clock(enum plls pll)
549 {
550     u64 mfi, mfn, mfd, pdf, ref_clk, pll_out, sign;
551     u64 reg = readl(pll);
552
553     pdf = (reg >> 26) & 0xF;
554     mfd = (reg >> 16) & 0x3FF;
555     mfi = (reg >> 10) & 0xF;
556     mfi = (mfi <= 5) ? 5: mfi;
557     mfn = reg & 0x3FF;
558     sign = (mfn < 512) ? 0: 1;
559     mfn = (mfn < 512) ? mfn: (1024 - mfn);
560
561     ref_clk = g_clock_src;
562
563     if (sign == 0) {
564         pll_out = (2 * ref_clk * mfi + ((2 * ref_clk * mfn) / (mfd + 1))) /
565                   (pdf + 1);
566     } else {
567         pll_out = (2 * ref_clk * mfi - ((2 * ref_clk * mfn) / (mfd + 1))) /
568                   (pdf + 1);
569     }
570
571     return (u32)pll_out;
572 }
573
574 /*!
575  * This function returns the main clock value in Hz.
576  */
577 u32 get_main_clock(enum main_clocks clk)
578 {
579     u32 ipg_pdf, nfc_pdf, hsp_podf;
580     u32 pll, ret_val = 0, usb_prdf, usb_podf, pdf;
581
582     u32 reg = readl(CCM_BASE_ADDR + CLKCTL_PDR0);
583     u32 reg4 = readl(CCM_BASE_ADDR + CLKCTL_PDR4);
584
585     if (system_rev & (0x2 << 4)) /* consumer path only in TO2.0 */
586             reg |= 0x1;
587
588     switch (clk) {
589     case CPU_CLK:
590         ret_val = get_arm_ahb_clock(1, reg);
591         break;
592     case AHB_CLK:
593         ret_val = get_arm_ahb_clock(0, reg); 
594         break;
595     case HSP_CLK:
596         if( reg & CLKMODE_CONSUMER) {
597                 hsp_podf = (reg >> 20) & 0x3;
598                 pll = get_arm_ahb_clock(1, reg);
599                 hsp_podf = hsp_div_table[hsp_podf][(reg>>16)&0xF];
600                 if(hsp_podf > 0 ) {
601                         ret_val = pll / hsp_podf;
602                 } else {
603                         diag_printf("mismatch HSP with ARM clock setting\n");
604                         ret_val = 0;
605                 }
606         } else {
607                 ret_val = get_arm_ahb_clock(0, reg); 
608         }
609         break;
610     case IPG_CLK:
611         ret_val = get_arm_ahb_clock(0, reg) / 2; 
612         break;
613     case IPG_PER_CLK:
614         if(reg & 0x04000000) {
615                 ipg_pdf = (reg >> 12) & 0x7;
616                 ret_val = get_arm_ahb_clock(0, reg)/ (ipg_pdf + 1);
617         } else {
618                 pdf = (((reg4 >> 16) & 0x7) + 1);
619                 ipg_pdf = (((reg4 >> 19) & 0x7) + 1);
620                 ret_val = get_arm_ahb_clock(1, reg)/(pdf * ipg_pdf);
621         }
622         break;
623     case NFC_CLK:
624         nfc_pdf = (reg4 >> 28) & 0xF;
625         pll = get_arm_ahb_clock(0, reg);
626         /* AHB/nfc_pdf */
627         ret_val = pll / (nfc_pdf + 1);
628         break;
629     case USB_CLK:
630         usb_prdf = (reg4 >> 25) & 0x7;
631         usb_podf = (reg4 >> 22) & 0x7;
632         if(reg4 & 0x200) {
633                 pll = get_arm_ahb_clock(1, reg);
634         } else {
635                 pll = pll_clock(PER_PLL);
636         }
637         ret_val = pll / ((usb_prdf + 1) * (usb_podf + 1));
638         break;
639     default:
640         diag_printf("Unknown clock: %d\n", clk);
641         break;
642     }
643
644     return ret_val;
645 }
646
647 /*!
648  * This function returns the peripheral clock value in Hz.
649  */
650 u32 get_peri_clock(enum peri_clocks clk)
651 {
652     u32 ret_val = 0, pdf, pre_pdf, clk_sel;
653     u32 mpdr2 = readl(CCM_BASE_ADDR + CLKCTL_PDR2);
654     u32 mpdr3 = readl(CCM_BASE_ADDR + CLKCTL_PDR3);
655     u32 mpdr4 = readl(CCM_BASE_ADDR + CLKCTL_PDR4);
656
657     switch (clk) {
658     case UART1_BAUD:
659     case UART2_BAUD:
660     case UART3_BAUD:
661         clk_sel = mpdr3 & (1 << 14);
662         pre_pdf = (mpdr4 >> 13) & 0x7;
663         pdf = (mpdr4 >> 10) & 0x7;
664         ret_val = ((clk_sel != 0) ? get_main_clock(CPU_CLK) :
665                   pll_clock(PER_PLL)) / ((pre_pdf + 1) * (pdf + 1));
666         break;
667     case SSI1_BAUD:
668         pre_pdf = (mpdr2 >> 24) & 0x7;
669         pdf = mpdr2 & 0x3F;
670         clk_sel = mpdr2 & ( 1 << 6);
671         ret_val = ((clk_sel != 0) ? get_main_clock(CPU_CLK) :
672                   pll_clock(PER_PLL)) / ((pre_pdf + 1) * (pdf + 1));
673         break;
674     case SSI2_BAUD:
675         pre_pdf = (mpdr2 >> 27) & 0x7;
676         pdf = (mpdr2 >> 8)& 0x3F;
677         clk_sel = mpdr2 & ( 1 << 6);
678         ret_val = ((clk_sel != 0) ? get_main_clock(CPU_CLK) :
679                   pll_clock(PER_PLL)) / ((pre_pdf + 1) * (pdf + 1));
680         break;
681     case CSI_BAUD:
682         clk_sel = mpdr2 & (1 << 7);
683         pre_pdf = (mpdr2 >> 16) & 0x7;
684         pdf = (mpdr2 >> 19) & 0x7;
685         ret_val = ((clk_sel != 0) ? get_main_clock(CPU_CLK) :
686                   pll_clock(PER_PLL)) / ((pre_pdf + 1) * (pdf + 1));
687         break;
688     case MSHC_CLK:
689         
690         pre_pdf = readl(CCM_BASE_ADDR + CLKCTL_PDR1);
691         clk_sel = (pre_pdf & 0x80);
692         pdf = (pre_pdf >> 22) & 0x3F;
693         pre_pdf = (pre_pdf >> 28) & 0x7;
694         ret_val = ((clk_sel != 0)? get_main_clock(CPU_CLK) :
695                 pll_clock(PER_PLL)) / ((pre_pdf + 1) * (pdf + 1));
696         break;
697     case ESDHC1_CLK:
698         clk_sel = mpdr3 & 0x40;
699         pre_pdf = mpdr3&0x7;
700         pdf = (mpdr3>>3)&0x7;
701         ret_val = ((clk_sel != 0)? get_main_clock(CPU_CLK) :
702                 pll_clock(PER_PLL)) / ((pre_pdf + 1) * (pdf + 1));
703         break;
704     case ESDHC2_CLK:
705         clk_sel = mpdr3 & 0x40;
706         pre_pdf = (mpdr3 >> 8)&0x7;
707         pdf = (mpdr3 >> 11)&0x7;
708         ret_val = ((clk_sel != 0)? get_main_clock(CPU_CLK) :
709                 pll_clock(PER_PLL)) / ((pre_pdf + 1) * (pdf + 1));
710         break;
711     case ESDHC3_CLK:
712         clk_sel = mpdr3 & 0x40;
713         pre_pdf = (mpdr3 >> 16)&0x7;
714         pdf = (mpdr3 >> 19)&0x7;
715         ret_val = ((clk_sel != 0)? get_main_clock(CPU_CLK) :
716                 pll_clock(PER_PLL)) / ((pre_pdf + 1) * (pdf + 1));
717         break;
718     case SPDIF_CLK:
719         clk_sel = mpdr3 & 0x400000;
720         pre_pdf = (mpdr3 >> 29)&0x7;
721         pdf = (mpdr3 >> 23)&0x3F;
722         ret_val = ((clk_sel != 0)? get_main_clock(CPU_CLK) :
723                 pll_clock(PER_PLL)) / ((pre_pdf + 1) * (pdf + 1));
724         break;
725     default:
726         diag_printf("%s(): This clock: %d not supported yet \n",
727                     __FUNCTION__, clk);
728         break;
729     }
730     return ret_val;
731 }
732
733 RedBoot_cmd("clko",
734             "Select clock source for CLKO (J11 on the CPU daughter card)",
735             " Default is 1/32 of ARM core\n\
736           <00> - display current clko selection \n\
737           <01> - async 32K clock \n\
738           <02> - input 24Mhz clock for pll ref(PLL_REF_CLK)\n\
739           <03> - input 24.576Mhz osc audio clk(AUDIO_REF_CLK) \n\
740           <04> - 1/32 mpll_divgen output 2x(MPLL_OUTPUT_2) \n\
741           <05> - 1/32 ppll_divgen output 0.75x(PPLL_OUTPUT_1) \n\
742           <06> - 1/32 mpll_divgen output 1x(MPLL_OUTPUT_1) \n\
743           <07> - 1/32 ppll output clock(PPLL) \n\
744           <08> - 1/32 arm clock(ARM_CLK) \n\
745           <09> - hclk always(AHB_CLK) \n\
746           <10> - ipg clock always(IPG_CLK) \n\
747           <11> - synched per clock root(PER_CLK) \n\
748           <12> - usb clock(USB_CLK) \n\
749           <13> - esdhc1 clock root (ESDHC_CLK) \n\
750           <14> - ssi clock root (SSI_CLK) \n\
751           <15> - mlb memory clock (MLB_CLK) \n\
752           <16> - csi clock root (ESDHC_CLK) \n\
753           <17> - spdif clock root (ESDHC_CLK) \n\
754           <18> - uart clock root (ESDHC_CLK) \n\
755           <19> - asrc autio input clock(ASRC_CLK) \n\
756           <20> - dptc reference clock 1 from ref cir(DPTC_REF_CLK)",
757             clko
758            );
759
760 static u8* clko_name[] ={
761     "NULL",
762     "async 32K clock",
763     "input 24Mhz clock for pll ref(PLL_REF_CLK)",
764     "input 24.576Mhz osc audio clk(AUDIO_REF_CLK)",
765     "1/32 mpll_divgen output 2x(MPLL_OUTPUT_2)",
766     "1/32 ppll_divgen output 0.75x(PPLL_OUTPUT_1)",
767     "1/32 mpll_divgen output 1x(MPLL_OUTPUT_1)",
768     "1/32 ppll output clock(PPLL)",
769     "1/32 arm clock(ARM_CLK)",
770     "hclk always(AHB_CLK)",
771     "ipg clock always(IPG_CLK)",
772     "synched per clock root(PER_CLK)",
773     "usb clock(USB_CLK)",
774     "esdhc1 clock root (ESDHC_CLK)",
775     "ssi clock root (SSI_CLK)" ,
776     "mlb memory clock (MLB_CLK)" ,
777     "mpll lock flag" ,
778     "csi clock root (ESDHC_CLK)" ,
779     "spdif clock root (ESDHC_CLK)",
780     "uart clock root (ESDHC_CLK)" ,
781     "asrc autio input clock(ASRC_CLK)",
782     "dptc reference clock 1 from ref cir(DPTC_REF_CLK)",
783 };
784
785 #define CLKO_MAX_INDEX          (sizeof(clko_name) / sizeof(u8*))
786
787 static void clko(int argc,char *argv[])
788 {
789     u32 action = 0, cosr;
790
791     if (!scan_opts(argc, argv, 1, 0, 0, (void*) &action,
792                    OPTION_ARG_TYPE_NUM, "action"))
793         return;
794
795     if (action >= (CLKO_MAX_INDEX -1)) {
796         diag_printf("%d is not supported\n\n", action);
797         return;
798     }
799
800     cosr = readl(CCM_BASE_ADDR + CLKCTL_COSR);
801     if (action != 0) {
802         cosr = (cosr & 0xFFFF0020) + ((action<16)?(action - 1):action);
803         if (action > 3 && action < 9) {
804             cosr |= 0x6C40; // make it divided by 32
805         }
806         writel(cosr, CCM_BASE_ADDR + CLKCTL_COSR);
807         diag_printf("Set clko to ");
808     }
809
810     cosr = readl(CCM_BASE_ADDR + CLKCTL_COSR);
811     if((cosr&0x1F) > 0x14) {
812         diag_printf("reserved selections\n");
813     } else { 
814         diag_printf("%s\n", clko_name[(cosr&0x1F)+1]);
815     }
816     diag_printf("COSR register[0x%x] = 0x%x\n",
817                 (CCM_BASE_ADDR + CLKCTL_COSR), cosr);
818 }
819
820 #ifdef L2CC_ENABLED
821 /*
822  * This command is added for some simple testing only. It turns on/off
823  * L2 cache regardless of L1 cache state. The side effect of this is
824  * when doing any flash operations such as "fis init", the L2
825  * will be turned back on along with L1 caches even though it is off
826  * by using this command.
827  */
828 RedBoot_cmd("L2",
829             "L2 cache",
830             "[ON | OFF]",
831             do_L2_caches
832            );
833
834 void do_L2_caches(int argc, char *argv[])
835 {
836     u32 oldints;
837     int L2cache_on=0;
838
839     if (argc == 2) {
840         if (strcasecmp(argv[1], "on") == 0) {
841             HAL_DISABLE_INTERRUPTS(oldints);
842             HAL_ENABLE_L2();
843             HAL_RESTORE_INTERRUPTS(oldints);
844         } else if (strcasecmp(argv[1], "off") == 0) {
845             HAL_DISABLE_INTERRUPTS(oldints);
846             HAL_CLEAN_INVALIDATE_L2();
847             HAL_DISABLE_L2();
848             HAL_RESTORE_INTERRUPTS(oldints);
849         } else {
850             diag_printf("Invalid L2 cache mode: %s\n", argv[1]);
851         }
852     } else {
853         HAL_L2CACHE_IS_ENABLED(L2cache_on);
854         diag_printf("L2 cache: %s\n", L2cache_on?"On":"Off");
855     }
856 }
857 #endif //L2CC_ENABLED
858
859 #define IIM_ERR_SHIFT       8
860 #define POLL_FUSE_PRGD      (IIM_STAT_PRGD | (IIM_ERR_PRGE << IIM_ERR_SHIFT))
861 #define POLL_FUSE_SNSD      (IIM_STAT_SNSD | (IIM_ERR_SNSE << IIM_ERR_SHIFT))
862
863 static void fuse_op_start(void)
864 {
865     /* Do not generate interrupt */
866     writel(0, IIM_BASE_ADDR + IIM_STATM_OFF);
867     // clear the status bits and error bits
868     writel(0x3, IIM_BASE_ADDR + IIM_STAT_OFF);
869     writel(0xFE, IIM_BASE_ADDR + IIM_ERR_OFF);
870 }
871
872 /*
873  * The action should be either:
874  *          POLL_FUSE_PRGD
875  * or:
876  *          POLL_FUSE_SNSD
877  */
878 static int poll_fuse_op_done(int action)
879 {
880
881     u32 status, error;
882
883     if (action != POLL_FUSE_PRGD && action != POLL_FUSE_SNSD) {
884         diag_printf("%s(%d) invalid operation\n", __FUNCTION__, action);
885         return -1;
886     }
887
888     /* Poll busy bit till it is NOT set */
889     while ((readl(IIM_BASE_ADDR + IIM_STAT_OFF) & IIM_STAT_BUSY) != 0 ) {
890     }
891
892     /* Test for successful write */
893     status = readl(IIM_BASE_ADDR + IIM_STAT_OFF);
894     error = readl(IIM_BASE_ADDR + IIM_ERR_OFF);
895
896     if ((status & action) != 0 && (error & (action >> IIM_ERR_SHIFT)) == 0) {
897         if (error) {
898             diag_printf("Even though the operation seems successful...\n");
899             diag_printf("There are some error(s) at addr=0x%x: 0x%x\n",
900                         (IIM_BASE_ADDR + IIM_ERR_OFF), error);
901         }
902         return 0;
903     }
904     diag_printf("%s(%d) failed\n", __FUNCTION__, action);
905     diag_printf("status address=0x%x, value=0x%x\n",
906                 (IIM_BASE_ADDR + IIM_STAT_OFF), status);
907     diag_printf("There are some error(s) at addr=0x%x: 0x%x\n",
908                 (IIM_BASE_ADDR + IIM_ERR_OFF), error);
909     return -1;
910 }
911
912 static void sense_fuse(int bank, int row, int bit)
913 {
914     int addr, addr_l, addr_h, reg_addr;
915
916     fuse_op_start();
917
918     addr = ((bank << 11) | (row << 3) | (bit & 0x7));
919     /* Set IIM Program Upper Address */
920     addr_h = (addr >> 8) & 0x000000FF;
921     /* Set IIM Program Lower Address */
922     addr_l = (addr & 0x000000FF);
923
924 #ifdef IIM_FUSE_DEBUG
925     diag_printf("%s: addr_h=0x%x, addr_l=0x%x\n",
926                 __FUNCTION__, addr_h, addr_l);
927 #endif
928     writel(addr_h, IIM_BASE_ADDR + IIM_UA_OFF);
929     writel(addr_l, IIM_BASE_ADDR + IIM_LA_OFF);
930     /* Start sensing */
931     writel(0x8, IIM_BASE_ADDR + IIM_FCTL_OFF);
932     if (poll_fuse_op_done(POLL_FUSE_SNSD) != 0) {
933         diag_printf("%s(bank: %d, row: %d, bit: %d failed\n",
934                     __FUNCTION__, bank, row, bit);
935     }
936     reg_addr = IIM_BASE_ADDR + IIM_SDAT_OFF;
937     diag_printf("fuses at (bank:%d, row:%d) = 0x%x\n", bank, row, readl(reg_addr));
938 }
939
940 void do_fuse_read(int argc, char *argv[])
941 {
942     int bank, row;
943
944     if (argc == 1) {
945         diag_printf("Useage: fuse_read <bank> <row>\n");
946         return;
947     } else if (argc == 3) {
948         if (!parse_num(*(&argv[1]), (unsigned long *)&bank, &argv[1], " ")) {
949                 diag_printf("Error: Invalid parameter\n");
950             return;
951         }
952         if (!parse_num(*(&argv[2]), (unsigned long *)&row, &argv[2], " ")) {
953                 diag_printf("Error: Invalid parameter\n");
954                 return;
955             }
956
957         diag_printf("Read fuse at bank:%d row:%d\n", bank, row);
958         sense_fuse(bank, row, 0);
959
960     } else {
961         diag_printf("Passing in wrong arguments: %d\n", argc);
962         diag_printf("Useage: fuse_read <bank> <row>\n");
963     }
964 }
965
966 /* Blow fuses based on the bank, row and bit positions (all 0-based)
967 */
968 static int fuse_blow(int bank,int row,int bit)
969 {
970     int addr, addr_l, addr_h, ret = -1;
971
972     fuse_op_start();
973
974     /* Disable IIM Program Protect */
975     writel(0xAA, IIM_BASE_ADDR + IIM_PREG_P_OFF);
976
977     addr = ((bank << 11) | (row << 3) | (bit & 0x7));
978     /* Set IIM Program Upper Address */
979     addr_h = (addr >> 8) & 0x000000FF;
980     /* Set IIM Program Lower Address */
981     addr_l = (addr & 0x000000FF);
982
983 #ifdef IIM_FUSE_DEBUG
984     diag_printf("blowing addr_h=0x%x, addr_l=0x%x\n", addr_h, addr_l);
985 #endif
986
987     writel(addr_h, IIM_BASE_ADDR + IIM_UA_OFF);
988     writel(addr_l, IIM_BASE_ADDR + IIM_LA_OFF);
989     /* Start Programming */
990     writel(0x31, IIM_BASE_ADDR + IIM_FCTL_OFF);
991     if (poll_fuse_op_done(POLL_FUSE_PRGD) == 0) {
992         ret = 0;
993     }
994
995     /* Enable IIM Program Protect */
996     writel(0x0, IIM_BASE_ADDR + IIM_PREG_P_OFF);
997     return ret;
998 }
999
1000 /*
1001  * This command is added for burning IIM fuses
1002  */
1003 RedBoot_cmd("fuse_read",
1004             "read some fuses",
1005             "<bank> <row>",
1006             do_fuse_read
1007            );
1008
1009 RedBoot_cmd("fuse_blow",
1010             "blow some fuses",
1011             "<bank> <row> <value>",
1012             do_fuse_blow
1013            );
1014
1015 #define         INIT_STRING              "12345678"
1016 static char ready_to_blow[] = INIT_STRING;
1017
1018 void quick_itoa(u32 num, char *a)
1019 {
1020     int i, j, k;
1021     for (i = 0; i <= 7; i++) {
1022         j = (num >> (4 * i)) & 0xF;
1023         k = (j < 10) ? '0' : ('a' - 0xa);
1024         a[i] = j + k;
1025     }
1026 }
1027
1028 void do_fuse_blow(int argc, char *argv[])
1029 {
1030     int bank, row, value, i;
1031
1032     if (argc == 1) {
1033         diag_printf("It is too dangeous for you to use this command.\n");
1034         return;
1035     } else if (argc == 2) {
1036         if (strcasecmp(argv[1], "nandboot") == 0) {
1037             quick_itoa(readl(EPIT_BASE_ADDR + EPITCNR), ready_to_blow);
1038             diag_printf("%s\n", ready_to_blow);
1039         }
1040         return;
1041     } else if (argc == 3) {
1042         if (strcasecmp(argv[1], "nandboot") == 0 &&
1043             strcasecmp(argv[2], ready_to_blow) == 0) {
1044 #if defined(CYGPKG_HAL_ARM_MXC91131) || defined(CYGPKG_HAL_ARM_MX21) || defined(CYGPKG_HAL_ARM_MX27) || defined(CYGPKG_HAL_ARM_MX31) ||defined(CYGPKG_HAL_ARM_MX35)
1045             diag_printf("No need to blow any fuses for NAND boot on this platform\n\n");
1046 #else
1047             diag_printf("Ready to burn NAND boot fuses\n");
1048             if (fuse_blow(0, 16, 1) != 0 || fuse_blow(0, 16, 7) != 0) {
1049                 diag_printf("NAND BOOT fuse blown failed miserably ...\n");
1050             } else {
1051                 diag_printf("NAND BOOT fuse blown successfully ...\n");
1052             }
1053         } else {
1054             diag_printf("Not ready: %s, %s\n", argv[1], argv[2]);
1055 #endif
1056         }
1057     } else if (argc == 4) {
1058         if (!parse_num(*(&argv[1]), (unsigned long *)&bank, &argv[1], " ")) {
1059                 diag_printf("Error: Invalid parameter\n");
1060                 return;
1061         }
1062         if (!parse_num(*(&argv[2]), (unsigned long *)&row, &argv[2], " ")) {
1063                 diag_printf("Error: Invalid parameter\n");
1064                 return;
1065         }
1066         if (!parse_num(*(&argv[3]), (unsigned long *)&value, &argv[3], " ")) {
1067                 diag_printf("Error: Invalid parameter\n");
1068                 return;
1069         }
1070
1071         diag_printf("Blowing fuse at bank:%d row:%d value:%d\n",
1072                     bank, row, value);
1073         for (i = 0; i < 8; i++) {
1074             if (((value >> i) & 0x1) == 0) {
1075                 continue;
1076             }
1077             if (fuse_blow(bank, row, i) != 0) {
1078                 diag_printf("fuse_blow(bank: %d, row: %d, bit: %d failed\n",
1079                             bank, row, i);
1080             } else {
1081                 diag_printf("fuse_blow(bank: %d, row: %d, bit: %d successful\n",
1082                             bank, row, i);
1083             }
1084         }
1085         sense_fuse(bank, row, 0);
1086
1087     } else {
1088         diag_printf("Passing in wrong arguments: %d\n", argc);
1089     }
1090     /* Reset to default string */
1091     strcpy(ready_to_blow, INIT_STRING);;
1092 }
1093
1094 /* precondition: m>0 and n>0.  Let g=gcd(m,n). */
1095 int gcd(int m, int n)
1096 {
1097     int t;
1098     while(m > 0) {
1099         if(n > m) {t = m; m = n; n = t;} /* swap */
1100         m -= n;
1101     }
1102     return n;
1103 }
1104
1105 #define CLOCK_SRC_DETECT_MS         100
1106 #define CLOCK_SRC_DETECT_MARGIN     500000
1107 void mxc_show_clk_input(void)
1108 {
1109
1110     u32 c1, c2, diff, ipg_real, ipg_clk = get_main_clock(IPG_CLK);
1111     u32 reg = readl(CCM_BASE_ADDR + CLKCTL_PDR0);
1112
1113     if (system_rev & (0x2 << 4)) /* consumer path only in TO2.0 */
1114             reg |= 0x1;
1115
1116     diag_printf("Chip is working in %s mode\n", (reg&CLKMODE_CONSUMER)?"consumer":"auto");
1117
1118     // enable GPT with IPG clock input
1119     writel(0x241, GPT_BASE_ADDR + GPTCR);
1120     // prescaler = 1
1121     writel(0, GPT_BASE_ADDR + GPTPR);
1122
1123     c1 = readl(GPT_BASE_ADDR + GPTCNT);
1124     // use 32KHz input clock to get the delay
1125     hal_delay_us(CLOCK_SRC_DETECT_MS * 1000);
1126     c2 = readl(GPT_BASE_ADDR + GPTCNT);
1127     diff = (c2 > c1) ? (c2 - c1) : (0xFFFFFFFF - c1 + c2);
1128     ipg_real = diff * 10;
1129
1130     if (ipg_real > (ipg_clk + CLOCK_SRC_DETECT_MARGIN)) {
1131         goto warning;
1132     } else if (ipg_real < (ipg_clk - CLOCK_SRC_DETECT_MARGIN)) {
1133         goto warning;
1134     }
1135     return;
1136 warning:
1137     diag_printf("Error: Actural ipg clock input is %d Hz\n", ipg_real);
1138     diag_printf("       ipg_clk=%d difference=%d\n\n",
1139                     ipg_clk,  (ipg_clk > ipg_real) ? (ipg_clk-ipg_real) : (ipg_real-ipg_clk));
1140     hal_delay_us(2000000);
1141 }
1142
1143 RedBoot_init(mxc_show_clk_input, RedBoot_INIT_LAST);