imx27: commit missed patch for workaround for ENGcm11563
[karo-tx-redboot.git] / packages / hal / arm / mx27 / 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             6               // See TLSbo80174
56 #define PLL_MFD_MAX             1024    //actual mfd+1
57 #define PLL_MFN_MAX             1022
58 #define PLL_MFN_MAX_2   510
59 #define PRESC_MAX               8
60 #define IPG_DIV_MAX             2
61 #define AHB_DIV_MAX             16
62 #define ARM_DIV_MAX             4
63
64 #define CPLM_SETUP              0
65
66 #define PLL_FREQ_MAX    (2 * PLL_REF_CLK * PLL_MFI_MAX)
67 #define PLL_FREQ_MIN    ((2 * PLL_REF_CLK * PLL_MFI_MIN) / PLL_PD_MAX)
68 #define AHB_CLK_MAX             133333333
69 #define IPG_CLK_MAX             (AHB_CLK_MAX / 2)
70 #define NFC_CLK_MAX             33333333
71
72 #define ERR_WRONG_CLK   -1
73 #define ERR_NO_MFI              -2
74 #define ERR_NO_MFN              -3
75 #define ERR_NO_PD               -4
76 #define ERR_NO_PRESC    -5
77
78 u32 pll_clock(enum plls pll);
79 u32 get_main_clock(enum main_clocks clk);
80 u32 get_peri_clock(enum peri_clocks clk);
81
82 static u32 pll_mfd_fixed;
83
84 static void clock_setup(int argc, char *argv[]);
85 static void clko(int argc, char *argv[]);
86 extern unsigned int g_clock_src;
87 extern unsigned int system_rev;
88 extern int sys_ver;
89
90 #define MXC_PERCLK_NUM  4
91
92 #ifdef CYGOPT_MX27_WORKAROUND_ENGcm11563
93 #define avoid_arm_src 1
94 #else
95 #define avoid_arm_src 0
96 #endif
97
98 RedBoot_cmd("clock",
99                         "Setup/Display clock (max AHB=133MHz, max IPG=66.5MHz)\nSyntax:",
100                         "[<core clock in MHz> [:<AHB-to-core divider>[:<IPG-to-AHB divider>]]]\n\n"
101                         "If a divider is zero or no divider is specified, the optimum divider values\n"
102                         "will be chosen. Examples:\n"
103                         "   [clock]         -> Show various clocks\n"
104                         "   [clock 266]     -> Core=266  AHB=133           IPG=66.5\n"
105                         "   [clock 350]     -> Core=350  AHB=117           IPG=58.5\n"
106                         "   [clock 266:4]   -> Core=266  AHB=66.5(Core/4)  IPG=66.5\n"
107                         "   [clock 266:4:2] -> Core=266  AHB=66.5(Core/4)  IPG=33.25(AHB/2)\n",
108                         clock_setup
109         );
110
111 /*!
112  * This is to calculate various parameters based on reference clock and
113  * targeted clock based on the equation:
114  *      t_clk = 2*ref_freq*(mfi + mfn/(mfd+1))/(pd+1)
115  * This calculation is based on a fixed MFD value for simplicity.
116  *
117  * @param ref       reference clock freq
118  * @param target    targeted clock in HZ
119  * @param p_pd      calculated pd value (pd value from register + 1) upon return
120  * @param p_mfi     calculated actual mfi value upon return
121  * @param p_mfn     calculated actual mfn value upon return
122  * @param p_mfd     fixed mfd value (mfd value from register + 1) upon return
123  *
124  * @return          0 if successful; non-zero otherwise.
125  */
126 int calc_pll_params(u32 ref, u32 target, int *p_pd,
127                                         int *p_mfi, int *p_mfn, int *p_mfd)
128 {
129         int pd, mfi, mfn;
130         u64 n_target = target, n_ref = ref;
131
132         if (g_clock_src == FREQ_26MHZ) {
133                 pll_mfd_fixed = 26 * 16;
134         } else if (g_clock_src == FREQ_27MHZ) {
135                 pll_mfd_fixed = 27 * 16;
136         } else {
137                 pll_mfd_fixed = 512;
138         }
139
140         // Make sure targeted freq is in the valid range. Otherwise the
141         // following calculation might be wrong!!!
142         if (target < PLL_FREQ_MIN || target > PLL_FREQ_MAX) {
143                 return ERR_WRONG_CLK;
144         }
145         // Use n_target and n_ref to avoid overflow
146         for (pd = 1; pd <= PLL_PD_MAX; pd++) {
147                 mfi = (n_target * pd) / (2 * n_ref);
148                 if (mfi > PLL_MFI_MAX) {
149                         return ERR_NO_MFI;
150                 } else if (mfi < PLL_MFI_MIN) {
151                         continue;
152                 }
153                 break;
154         }
155         // Now got pd and mfi already
156         mfn = (((n_target * pd) / 2 - n_ref * mfi) * pll_mfd_fixed) / n_ref;
157         // Check mfn within limit and mfn < denominator
158         if (sys_ver == SOC_SILICONID_Rev1_0) {
159                 if (mfn < 0 || mfn > PLL_MFN_MAX || mfn >= pll_mfd_fixed) {
160                         return ERR_NO_MFN;
161                 }
162         } else {
163                 if (mfn < -PLL_MFN_MAX_2 || mfn > PLL_MFN_MAX_2 || mfn >= pll_mfd_fixed) {
164                         return ERR_NO_MFN;
165                 }
166         }
167
168         if (pd > PLL_PD_MAX) {
169                 return ERR_NO_PD;
170         }
171         *p_pd = pd;
172         *p_mfi = mfi;
173         *p_mfn = mfn;
174         *p_mfd = pll_mfd_fixed;
175         return 0;
176 }
177
178 static u32 per_clk_old[MXC_PERCLK_NUM];
179
180 /*!
181  * This function assumes the expected core clock has to be changed by
182  * modifying the PLL. This is NOT true always but for most of the times,
183  * it is. So it assumes the PLL output freq is the same as the expected
184  * core clock (presc=1) unless the core clock is less than PLL_FREQ_MIN.
185  * In the latter case, it will try to increase the presc value until
186  * (presc*core_clk) is greater than PLL_FREQ_MIN. It then makes call to
187  * calc_pll_params() and obtains the values of PD, MFI,MFN, MFD based
188  * on the targeted PLL and reference input clock to the PLL. Lastly,
189  * it sets the register based on these values along with the dividers.
190  * Note 1) There is no value checking for the passed-in divider values
191  *         so the caller has to make sure those values are sensible.
192  *      2) Also adjust the NFC divider such that the NFC clock doesn't
193  *         exceed NFC_CLK_MAX (which is 33MHz now).
194  *      3) Added feature to maintain the perclock before and after the call.
195  * !!!! 4) This function can't have printf in it since the serial i/f is
196  *         stopped.
197  *
198  * @param ref       pll input reference clock (32KHz or 26MHz)
199  * @param core_clk  core clock in Hz
200  * @param ahb_div   ahb divider to divide the core clock to get ahb clock
201  *                  (ahb_div - 1) needs to be set in the register
202  * @param ipg_div   ipg divider to divide the ahb clock to get ipg clock
203  *                  (ipg_div - 1) needs to be set in the register
204  # @return          0 if successful; non-zero otherwise
205  */
206 #define CMD_CLOCK_DEBUG
207 int configure_clock(u32 ref, u32 core_clk, u32 ahb_div, u32 ipg_div)
208 {
209         u32 pll, presc = 1;
210         int pd, mfi, mfn, mfd;
211         u32 cscr, mpctl0;
212         u32 pcdr0, nfc_div, hdiv, nfc_div_factor;
213         u32 per_div[MXC_PERCLK_NUM];
214         int ret, i, arm_src = 0;
215
216         per_clk_old[0] = get_peri_clock(PER_CLK1);
217         per_clk_old[1] = get_peri_clock(PER_CLK2);
218         per_clk_old[2] = get_peri_clock(PER_CLK3);
219         per_clk_old[3] = get_peri_clock(PER_CLK4);
220         diag_printf("per1=%9u\n", per_clk_old[0]);
221         diag_printf("per2=%9u\n", per_clk_old[1]);
222         diag_printf("per3=%9u\n", per_clk_old[2]);
223         diag_printf("per4=%9u\n", per_clk_old[3]);
224         // assume pll default to core clock first
225         if (sys_ver == SOC_SILICONID_Rev1_0) {
226                 pll = core_clk;
227                 nfc_div_factor = 1;
228         } else {
229                 if (!avoid_arm_src && core_clk > 266 * SZ_DEC_1M) {
230                         pll = core_clk;
231                         arm_src = 1;
232                 } else {
233                         pll = core_clk * 3 / 2;
234                 }
235                 nfc_div_factor = ahb_div;
236         }
237
238         // when core_clk >= PLL_FREQ_MIN, the presc can be 1.
239         // Otherwise, need to calculate presc value below and adjust the targeted pll
240         if (pll < PLL_FREQ_MIN) {
241                 int presc_max;
242
243                 if (sys_ver == SOC_SILICONID_Rev1_0) {
244                         presc_max = PRESC_MAX;
245                 } else {
246                         presc_max = ARM_DIV_MAX;
247                 }
248
249                 for (presc = 1; presc <= presc_max; presc++) {
250                         if (pll * presc > PLL_FREQ_MIN) {
251                                 break;
252                         }
253                 }
254                 if (presc == presc_max + 1) {
255                         diag_printf("can't make presc=%d\n", presc);
256                         return ERR_NO_PRESC;
257                 }
258                 if (sys_ver == SOC_SILICONID_Rev1_0) {
259                         pll = core_clk * presc;
260                 } else {
261                         pll = 3 * core_clk * presc / 2;
262                 }
263         }
264         // pll is now the targeted pll output. Use it along with ref input clock
265         // to get pd, mfi, mfn, mfd
266         if ((ret = calc_pll_params(ref, pll, &pd, &mfi, &mfn, &mfd)) != 0) {
267 #ifdef CMD_CLOCK_DEBUG
268                 diag_printf("can't find pll parameters: %d\n", ret);
269 #endif
270                 return ret;
271         }
272 #ifdef CMD_CLOCK_DEBUG
273         diag_printf("ref=%d, pll=%d, pd=%d, mfi=%d,mfn=%d, mfd=%d\n",
274                                 ref, pll, pd, mfi, mfn, mfd);
275 #endif
276
277         // blindly increase divider first to avoid too fast ahbclk and ipgclk
278         // in case the core clock increases too much
279         cscr = readl(SOC_CRM_CSCR);
280         if (sys_ver == SOC_SILICONID_Rev1_0) {
281                 hdiv = (pll + AHB_CLK_MAX - 1) / AHB_CLK_MAX;
282                 cscr = (cscr & ~0x0000FF00) | ((hdiv - 1) << 9) | (1 << 8);
283         } else {
284                 if (core_clk > 266 * SZ_DEC_1M) {
285                         hdiv = (pll + AHB_CLK_MAX - 1) / AHB_CLK_MAX;
286                 } else {
287                         hdiv = (2 * pll + 3 * AHB_CLK_MAX - 1) / (3 * AHB_CLK_MAX);
288                 }
289                 cscr = (cscr & ~0x0000FF00) | ((hdiv - 1) << 8);
290         }
291         writel(cscr, SOC_CRM_CSCR);
292
293         // update PLL register
294         if (!((mfd < 10 * mfn) && (10 * mfn < 9 * mfd)))
295                 writel(1 << 6, SOC_CRM_MPCTL1);
296
297         mpctl0 = readl(SOC_CRM_MPCTL0);
298         mpctl0 = (mpctl0 & 0xC000C000)  |
299                 CPLM_SETUP                         |
300                 ((pd - 1) << 26)           |
301                 ((mfd - 1) << 16)          |
302                 (mfi << 10)                        |
303                 mfn;
304         writel(mpctl0, SOC_CRM_MPCTL0);
305
306         // restart mpll
307         writel((cscr | (1 << 18)), SOC_CRM_CSCR);
308         // check the LF bit to insure lock
309         while ((readl(SOC_CRM_MPCTL1) & (1 << 15)) == 0);
310         // have to add some delay for new values to take effect
311         for (i = 0; i < 100000; i++);
312
313         // PLL locked already so use the new divider values
314         cscr = readl(SOC_CRM_CSCR);
315         cscr &= ~0x0000FF00;
316
317         if (sys_ver == SOC_SILICONID_Rev1_0) {
318                 cscr |= ((presc - 1) << 13) | ((ahb_div - 1) << 9) | ((ipg_div - 1) << 8);
319         } else {
320                 cscr |= (arm_src << 15) | ((presc - 1) << 12) | ((ahb_div - 1) << 8);
321         }
322         writel(cscr, SOC_CRM_CSCR);
323
324         // Make sure optimal NFC clock but less than NFC_CLK_MAX
325         for (nfc_div = 1; nfc_div <= 16; nfc_div++) {
326                 if ((core_clk / (nfc_div_factor * nfc_div)) <= NFC_CLK_MAX) {
327                         break;
328                 }
329         }
330         pcdr0 = readl(SOC_CRM_PCDR0);
331         if (sys_ver == SOC_SILICONID_Rev1_0) {
332                 writel(((pcdr0 & 0xFFFF0FFF) | ((nfc_div - 1) << 12)),
333                         SOC_CRM_PCDR0);
334         } else {
335                 writel(((pcdr0 & 0xFFFFF3CF) | ((nfc_div - 1) << 6)),
336                         SOC_CRM_PCDR0);
337         }
338
339         if (sys_ver == SOC_SILICONID_Rev1_0) {
340                 pll = pll_clock(MCU_PLL) + 500000;
341         } else {
342                 if (core_clk > (266 * SZ_DEC_1M)) {
343                         pll = pll_clock(MCU_PLL) + 500000;
344                 } else {
345                         pll = 2 * pll_clock(MCU_PLL) / 3 + 500000;
346                 }
347         }
348         for (i = 0; i < MXC_PERCLK_NUM; i++) {
349                 per_div[i] = (pll / per_clk_old[i]) - 1;
350         }
351         writel((per_div[3] << 24) | (per_div[2] << 16) | (per_div[1] << 8) |
352                 (per_div[0]), SOC_CRM_PCDR1);
353
354         return 0;
355 }
356
357 static void clock_setup(int argc, char *argv[])
358 {
359         u32 i, core_clk, ipg_div, data[3], ahb_div, ahb_clk, ahb_clk_in, ipg_clk;
360         u32 presc_max,  ahb_div_max, pll;
361         unsigned long temp;
362         int ret;
363
364         if (argc == 1)
365                 goto print_clock;
366         if (g_clock_src == FREQ_27MHZ) {
367                 diag_printf("Error: clock setup is not supported for 27MHz source\n");
368                 return;
369         }
370         for (i = 0;  i < 3;  i++) {
371                 if (!parse_num(argv[1], &temp, &argv[1], ":")) {
372                         diag_printf("Error: Invalid parameter\n");
373                         return;
374                 }
375                 data[i] = temp;
376         }
377
378         core_clk = data[0] * SZ_DEC_1M;
379         ahb_div = data[1];  // actual register field + 1
380         ipg_div = data[2];  // actual register field + 1
381
382         if (sys_ver == SOC_SILICONID_Rev1_0) {
383                 presc_max = PRESC_MAX;
384                 ahb_div_max = AHB_DIV_MAX;
385                 pll = core_clk;
386                 ahb_clk_in = core_clk;
387         } else {
388                 presc_max = ARM_DIV_MAX;
389                 ahb_div_max = AHB_DIV_MAX / ARM_DIV_MAX;
390                 if (core_clk > (266 * SZ_DEC_1M)) {
391                         pll = core_clk;
392                         ahb_clk_in = core_clk * 2 / 3;
393                 } else {
394                         pll = 3 * core_clk / 2;
395                         ahb_clk_in = core_clk;
396                 }
397                 ipg_div = 2;
398         }
399
400         if (pll < (PLL_FREQ_MIN / presc_max) || pll > PLL_FREQ_MAX) {
401                 diag_printf("Targeted core clock should be within [%d - %d]\n",
402                                         PLL_FREQ_MIN / presc_max, PLL_FREQ_MAX);
403                 return;
404         }
405
406         // find the ahb divider
407         if (ahb_div > ahb_div_max) {
408                 diag_printf("Invalid AHB divider: %d. Maximum value is %d\n",
409                                         ahb_div, ahb_div_max);
410                 return;
411         }
412         if (ahb_div == 0) {
413                 // no AHBCLK divider specified
414                 for (ahb_div = 1; ; ahb_div++) {
415                         if ((ahb_clk_in / ahb_div) <= AHB_CLK_MAX) {
416                                 break;
417                         }
418                 }
419         }
420         if (ahb_div > ahb_div_max || (ahb_clk_in / ahb_div) > AHB_CLK_MAX) {
421                 diag_printf("Can't make AHB=%d since max=%d\n",
422                                         core_clk / ahb_div, AHB_CLK_MAX);
423                 return;
424         }
425
426         // find the ipg divider
427         ahb_clk = ahb_clk_in / ahb_div;
428         if (ipg_div > IPG_DIV_MAX) {
429                 diag_printf("Invalid IPG divider: %d. Maximum value is %d\n",
430                                         ipg_div, IPG_DIV_MAX);
431                 return;
432         }
433         if (ipg_div == 0) {
434                 ipg_div++;                      // At least =1
435                 if (ahb_clk > IPG_CLK_MAX)
436                         ipg_div++;              // Make it =2
437         }
438         if (ipg_div > IPG_DIV_MAX || (ahb_clk / ipg_div) > IPG_CLK_MAX) {
439                 diag_printf("Can't make IPG=%d since max=%d\n",
440                                         (ahb_clk / ipg_div), IPG_CLK_MAX);
441                 return;
442         }
443         ipg_clk = ahb_clk / ipg_div;
444
445         diag_printf("Trying to set core=%d ahb=%d ipg=%d...\n",
446                                 core_clk, ahb_clk, ipg_clk);
447
448         // stop the serial to be ready to adjust the clock
449         hal_delay_us(100000);
450         cyg_hal_plf_serial_stop();
451         // adjust the clock
452         ret = configure_clock(PLL_REF_CLK, core_clk, ahb_div, ipg_div);
453         // restart the serial driver
454         cyg_hal_plf_serial_init();
455         hal_delay_us(100000);
456
457         if (ret != 0) {
458                 diag_printf("Failed to setup clock: %d\n", ret);
459                 return;
460         }
461
462         // check for new per clock settings and warn user if there is a change.
463         if (per_clk_old[0] != get_peri_clock(PER_CLK1)) {
464                 diag_printf("per_clk1 changed; old clock was: %u\n", per_clk_old[0]);
465         }
466         if (per_clk_old[1] != get_peri_clock(PER_CLK2)) {
467                 diag_printf("per_clk2 changed; old clock was: %u\n", per_clk_old[1]);
468         }
469         if (per_clk_old[2] != get_peri_clock(PER_CLK3)) {
470                 diag_printf("per_clk3 changed; old clock was: %u\n", per_clk_old[2]);
471         }
472         if (per_clk_old[3] != get_peri_clock(PER_CLK4)) {
473                 diag_printf("per_clk4 changed; old clock was: %u\n", per_clk_old[3]);
474         }
475
476         diag_printf("\n<<<New clock setting>>>\n");
477
478         // Now printing clocks
479 print_clock:
480         diag_printf("\nMPLL\t\tSPLL\n");
481         diag_printf("=========================\n");
482         diag_printf("%-16d%-16d\n\n", pll_clock(MCU_PLL), pll_clock(SER_PLL));
483         diag_printf("CPU\t\tAHB\t\tIPG\t\tNFC\t\tUSB\n");
484         diag_printf("========================================================================\n");
485         diag_printf("%-16d%-16d%-16d%-16d%-16d\n\n",
486                                 get_main_clock(CPU_CLK),
487                                 get_main_clock(AHB_CLK),
488                                 get_main_clock(IPG_CLK),
489                                 get_main_clock(NFC_CLK),
490                                 get_main_clock(USB_CLK));
491
492         diag_printf("PER1\t\tPER2\t\tPER3\t\tPER4\n");
493         diag_printf("===========================================");
494         diag_printf("=============\n");
495
496         diag_printf("%-16d%-16d%-16d%-16d\n\n",
497                                 get_peri_clock(PER_CLK1),
498                                 get_peri_clock(PER_CLK2),
499                                 get_peri_clock(PER_CLK3),
500                                 get_peri_clock(PER_CLK4));
501
502         diag_printf("H264\t\tMSHC\t\tSSI1\t\tSSI2\n");
503         diag_printf("========================================================\n");
504         diag_printf("%-16d%-16d%-16d%-16d\n\n",
505                                 get_peri_clock(H264_BAUD),
506                                 get_peri_clock(MSHC_BAUD),
507                                 get_peri_clock(SSI1_BAUD),
508                                 get_peri_clock(SSI2_BAUD));
509         diag_printf("PERCLK: 1-<UART|GPT|PWM> 2-<SDHC|CSPI> 3-<LCDC> 4-<CSI>\n");
510 }
511
512 /*!
513  * This function returns the PLL output value in Hz based on pll.
514  */
515 u32 pll_clock(enum plls pll)
516 {
517         int mfi, mfn, mfd, pdf;
518         u32 pll_out;
519         u32 reg = readl(pll);
520         u64 ref_clk;
521
522         if ((pll == SER_PLL) && (sys_ver == SOC_SILICONID_Rev2_0)) {
523                 writel(reg, pll);
524         }
525         pdf = (reg >> 26) & 0xF;
526         mfd = (reg >> 16) & 0x3FF;
527         mfi = (reg >> 10) & 0xF;
528         if (mfi < 5) {
529                 mfi = 5;
530         }
531         mfn = reg & 0x3FF;
532         if (mfn >= 512) {
533                 mfn = 1024 - mfn;
534         }
535         ref_clk = g_clock_src;
536
537         pll_out = (2 * ref_clk * mfi + ((2 * ref_clk * mfn) / (mfd + 1))) /
538                 (pdf + 1);
539
540         return pll_out;
541 }
542
543 /*!
544  * This function returns the main clock value in Hz.
545  */
546 u32 get_main_clock(enum main_clocks clk)
547 {
548         u32 presc, ahb_div, ipg_pdf, nfc_div;
549         u32 ret_val = 0, usb_div;
550         u32 cscr = readl(SOC_CRM_CSCR);
551         u32 pcdr0 = readl(SOC_CRM_PCDR0);
552
553         if (sys_ver == SOC_SILICONID_Rev1_0) {
554                 presc = ((cscr >> CRM_CSCR_PRESC_OFFSET) & 0x7) + 1;
555         } else {
556                 presc = ((cscr >> CRM_CSCR_ARM_OFFSET) & 0x3) + 1;
557         }
558
559         switch (clk) {
560         case CPU_CLK:
561                 if ((sys_ver == SOC_SILICONID_Rev1_0) || (cscr & CRM_CSCR_ARM_SRC)) {
562                         ret_val = pll_clock(MCU_PLL) / presc;
563                 } else {
564                         ret_val = 2 * pll_clock(MCU_PLL) / (3 * presc);
565                 }
566                 break;
567         case AHB_CLK:
568                 if (sys_ver == SOC_SILICONID_Rev1_0) {
569                         ahb_div = ((cscr >> CRM_CSCR_BCLKDIV_OFFSET) & 0xF) + 1;
570                         ret_val = pll_clock(MCU_PLL) / (presc * ahb_div);
571                 } else {
572                         ahb_div = ((cscr >> CRM_CSCR_AHB_OFFSET) & 0x3) + 1;
573                         ret_val = 2 * pll_clock(MCU_PLL) / (3 * ahb_div);
574                 }
575                 break;
576         case IPG_CLK:
577                 if (sys_ver == SOC_SILICONID_Rev1_0) {
578                         ahb_div = ((cscr >> CRM_CSCR_BCLKDIV_OFFSET) & 0xF) + 1;
579                         ipg_pdf = ((cscr >> CRM_CSCR_IPDIV_OFFSET) & 0x1) + 1;
580                         ret_val = pll_clock(MCU_PLL) / (presc * ahb_div * ipg_pdf);
581                 } else {
582                         ahb_div = ((cscr >> CRM_CSCR_AHB_OFFSET) & 0x3) + 1;
583                         ret_val = pll_clock(MCU_PLL) / (3 * ahb_div);
584                 }
585                 break;
586         case NFC_CLK:
587                 if (sys_ver == SOC_SILICONID_Rev1_0) {
588                         nfc_div = ((pcdr0 >> 12) & 0xF) + 1;
589                         /* AHB/nfc_div */
590                         ret_val = pll_clock(MCU_PLL) / (presc * nfc_div);
591                 } else {
592                         nfc_div = ((pcdr0 >> 6) & 0xF) + 1;
593                         ahb_div = ((cscr >> CRM_CSCR_AHB_OFFSET) & 0x3) + 1;
594                         ret_val = 2*pll_clock(MCU_PLL) / (3 * ahb_div * nfc_div);
595                 }
596                 break;
597         case USB_CLK:
598                 usb_div = ((cscr >> CRM_CSCR_USB_DIV_OFFSET) & 0x7) + 1;
599                 ret_val = pll_clock(SER_PLL) / usb_div;
600                 break;
601         default:
602                 diag_printf("Unknown clock: %d\n", clk);
603                 break;
604         }
605         return ret_val;
606 }
607
608 /*!
609  * This function returns the peripheral clock value in Hz.
610  */
611 u32 get_peri_clock(enum peri_clocks clk)
612 {
613         u32 ret_val = 0, div;
614         u32 pcdr0 = readl(SOC_CRM_PCDR0);
615         u32 pcdr1 = readl(SOC_CRM_PCDR1);
616         u32 cscr = readl(SOC_CRM_CSCR);
617
618         switch (clk) {
619         case PER_CLK1:
620                 div = (pcdr1 & 0x3F) + 1;
621                 if (sys_ver == SOC_SILICONID_Rev1_0) {
622                         ret_val = pll_clock(MCU_PLL) / div;
623                 } else {
624                         ret_val = 2 * pll_clock(MCU_PLL) / (3 * div);
625                 }
626                 break;
627         case PER_CLK2:
628         case SPI1_CLK:
629         case SPI2_CLK:
630                 div = ((pcdr1 >> 8) & 0x3F) + 1;
631                 if (sys_ver == SOC_SILICONID_Rev1_0) {
632                         ret_val = pll_clock(MCU_PLL) / div;
633                 } else {
634                         ret_val = 2 * pll_clock(MCU_PLL) / (3 * div);
635                 }
636                 break;
637         case PER_CLK3:
638                 div = ((pcdr1 >> 16) & 0x3F) + 1;
639                 if (sys_ver == SOC_SILICONID_Rev1_0) {
640                         ret_val = pll_clock(MCU_PLL) / div;
641                 } else {
642                         ret_val = 2 * pll_clock(MCU_PLL) / (3 * div);
643                 }
644                 break;
645         case PER_CLK4:
646                 div = ((pcdr1 >> 24) & 0x3F) + 1;
647                 if (sys_ver == SOC_SILICONID_Rev1_0) {
648                         ret_val = pll_clock(MCU_PLL) / div;
649                 } else {
650                         ret_val = 2 * pll_clock(MCU_PLL) / (3 * div);
651                 }
652                 break;
653         case SSI1_BAUD:
654                 div = (pcdr0 >> 16) & 0x3F;
655                 if (sys_ver == SOC_SILICONID_Rev1_0) {
656                         if (div < 2) {
657                                 div = 62 * 2;
658                         }
659                 } else {
660                         div += 4;
661                 }
662                 if ((cscr & (1 << 22)) != 0) {
663                         // This takes care of 0.5*SSIDIV[0] by x2
664                         if (sys_ver == SOC_SILICONID_Rev1_0) {
665                                 ret_val = (2 * pll_clock(MCU_PLL)) / div;
666                         } else {
667                                 ret_val = (4 * pll_clock(MCU_PLL)) / (3 * div);
668                         }
669                 } else {
670                         ret_val = (2 * pll_clock(SER_PLL)) / div;
671                 }
672                 break;
673         case SSI2_BAUD:
674                 div = (pcdr0 >> 26) & 0x3F;
675                 if (sys_ver == SOC_SILICONID_Rev1_0) {
676                         if (div < 2) {
677                                 div = 62 * 2;
678                         }
679                 } else {
680                         div += 4;
681                 }
682                 if ((cscr & (1 << 23)) != 0) {
683                         if (sys_ver == SOC_SILICONID_Rev1_0) {
684                                 ret_val = (2 * pll_clock(MCU_PLL)) / div;
685                         } else {
686                                 ret_val = (4 * pll_clock(MCU_PLL)) / (3 * div);
687                         }
688                 } else {
689                         ret_val = (2 * pll_clock(SER_PLL)) / div;
690                 }
691                 break;
692         case H264_BAUD:
693                 if (sys_ver == SOC_SILICONID_Rev1_0) {
694                         div = (pcdr0 >> 8) & 0xF;
695                         if (div < 2) {
696                                 div = 62 * 2;
697                         }
698                 } else {
699                         div = (pcdr0 >> 10) & 0x3F;
700                         div += 4;
701                 }
702                 if ((cscr & (1 << 21)) != 0) {
703                         if (sys_ver == SOC_SILICONID_Rev1_0) {
704                                 ret_val = (2 * pll_clock(MCU_PLL)) / div;
705                         } else {
706                                 ret_val = (4 * pll_clock(MCU_PLL)) / (3 * div);
707                         }
708                 } else {
709                         ret_val = (2 * pll_clock(SER_PLL)) / div;
710                 }
711                 break;
712         case MSHC_BAUD:
713                 if ((cscr & (1 << 20)) != 0) {
714                         if (sys_ver == SOC_SILICONID_Rev1_0) {
715                                 div = (pcdr0 & 0x1F) + 1;
716                                 ret_val = pll_clock(MCU_PLL) / div;
717                         } else {
718                                 div = (pcdr0 & 0x3F) + 1;
719                                 ret_val = 2 * pll_clock(MCU_PLL) / (3 * div);
720                         }
721                 } else {
722                         div = (pcdr0 & 0x1F) + 1;
723                         ret_val = (2 * pll_clock(SER_PLL)) / div;
724                 }
725                 break;
726         default:
727                 diag_printf("%s(): This clock: %d not supported yet\n",
728                                         __FUNCTION__, clk);
729                 break;
730         }
731
732         return ret_val;
733 }
734
735 RedBoot_cmd("clko",
736                         "Select clock source for CLKO (TP1 on EVB or S3 Pin 1)",
737                         " The output clock is the actual clock source freq divided by 8. Default is FCLK\n"
738                         "         Note that the module clock will be turned on for reading!\n"
739                         "          <0> - display current clko selection\n"
740                         "          <1> - CLK32\n"
741                         "          <2> - PREMCLK\n"
742                         "          <3> - CLK26M (may see nothing if 26MHz Crystal is not connected)\n"
743                         "          <4> - MPLL Reference CLK\n"
744                         "          <5> - SPLL Reference CLK\n"
745                         "          <6> - MPLL CLK\n"
746                         "          <7> - SPLL CLK\n"
747                         "          <8> - FCLK\n"
748                         "          <9> - AHBCLK\n"
749                         "          <10> - IPG_CLK (PERCLK)\n"
750                         "          <11> - PERCLK1\n"
751                         "          <12> - PERCLK2\n"
752                         "          <13> - PERCLK3\n"
753                         "          <14> - PERCLK4\n"
754                         "          <15> - SSI 1 Baud\n"
755                         "          <16> - SSI 2 Baud\n"
756                         "          <17> - NFC\n"
757                         "          <18> - MSHC Baud\n"
758                         "          <19> - H264 Baud\n"
759                         "          <20> - CLK60M Always\n"
760                         "          <21> - CLK32K Always\n"
761                         "          <22> - CLK60M\n"
762                         "          <23> - DPTC Ref",
763                         clko
764         );
765
766 static u8* clko_name[] = {
767         "NULL",
768         "CLK32",
769         "PREMCLK",
770         "CLK26M (may see nothing if 26MHz Crystal is not connected)",
771         "MPLL Reference CLK",
772         "SPLL Reference CLK",
773         "MPLL CLK",
774         "SPLL CLK",
775         "FCLK",
776         "AHBCLK",
777         "IPG_CLK (PERCLK)",
778         "PERCLK1",
779         "PERCLK2",
780         "PERCLK3",
781         "PERCLK4",
782         "SSI 1 Baud",
783         "SSI 2 Baud",
784         "NFC",
785         "MSHC Baud",
786         "H264 Baud",
787         "CLK60M Always",
788         "CLK32K Always",
789         "CLK60M",
790         "DPTC Ref",
791 };
792
793 #define CLKO_MAX_INDEX                  (sizeof(clko_name) / sizeof(u8*))
794
795 static void clko(int argc,char *argv[])
796 {
797         u32 action = 0, ccsr;
798
799         if (!scan_opts(argc, argv, 1, 0, 0, &action,
800                                         OPTION_ARG_TYPE_NUM, "action"))
801                 return;
802
803         if (action >= CLKO_MAX_INDEX) {
804                 diag_printf("%d is not supported\n", action);
805                 return;
806         }
807
808         ccsr = readl(SOC_CRM_CCSR);
809
810         if (action != 0) {
811                 ccsr = (ccsr & (~0x1F)) + action - 1;
812                 writel(ccsr, SOC_CRM_CCSR);
813                 diag_printf("Set clko to ");
814         }
815
816         ccsr = readl(SOC_CRM_CCSR);
817         diag_printf("%s\n", clko_name[(ccsr & 0x1F) + 1]);
818         diag_printf("CCSR register[0x%08lx] = 0x%08x\n", SOC_CRM_CCSR, ccsr);
819 }
820
821 extern int flash_program(void *_addr, void *_data, int len, void **err_addr);
822 extern int flash_erase(void *addr, int len, void **err_addr);
823
824 void auto_flash_start(void)
825 {
826         void *err_addr;
827         int stat;
828         int nor_update = 1; //todo: need to support NAND
829         u32 src = readl(SERIAL_DOWNLOAD_SRC_REG);
830         u32 dst = readl(SERIAL_DOWNLOAD_TGT_REG);
831         u32 sz = readl(SERIAL_DOWNLOAD_SZ_REG);
832
833         if (readl(SERIAL_DOWNLOAD_MAGIC_REG) != SERIAL_DOWNLOAD_MAGIC) {
834                 return;
835         }
836
837         if (nor_update) {
838                 // Erase area to be programmed
839                 if ((stat = flash_erase((void *)dst, sz, &err_addr)) != 0) {
840                         diag_printf("BEADDEAD\n");
841                         return;
842                 }
843                 diag_printf("BEADBEEF\n");
844                 // Now program it
845                 if ((stat = flash_program((void *)dst, (void *)src, sz,
846                                                                                 &err_addr)) != 0) {
847                         diag_printf("BEADFEEF\n");
848                 }
849         }
850         diag_printf("BEADCEEF\n");
851 }
852
853 RedBoot_init(auto_flash_start, RedBoot_INIT_LAST);
854
855 #define IIM_ERR_SHIFT           8
856 #define POLL_FUSE_PRGD          (IIM_STAT_PRGD | (IIM_ERR_PRGE << IIM_ERR_SHIFT))
857 #define POLL_FUSE_SNSD          (IIM_STAT_SNSD | (IIM_ERR_SNSE << IIM_ERR_SHIFT))
858
859 static void fuse_op_start(void)
860 {
861         /* Do not generate interrupt */
862         writel(0, IIM_BASE_ADDR + IIM_STATM_OFF);
863         // clear the status bits and error bits
864         writel(0x3, IIM_BASE_ADDR + IIM_STAT_OFF);
865         writel(0xFE, IIM_BASE_ADDR + IIM_ERR_OFF);
866 }
867
868 /*
869  * The action should be either:
870  *          POLL_FUSE_PRGD
871  * or:
872  *          POLL_FUSE_SNSD
873  */
874 static int poll_fuse_op_done(int action)
875 {
876         u32 status, error;
877
878         if (action != POLL_FUSE_PRGD && action != POLL_FUSE_SNSD) {
879                 diag_printf("%s(%d) invalid operation\n", __FUNCTION__, action);
880                 return -1;
881         }
882
883         /* Poll busy bit till it is NOT set */
884         while ((readl(IIM_BASE_ADDR + IIM_STAT_OFF) & IIM_STAT_BUSY) != 0 ) {
885         }
886
887         /* Test for successful write */
888         status = readl(IIM_BASE_ADDR + IIM_STAT_OFF);
889         error = readl(IIM_BASE_ADDR + IIM_ERR_OFF);
890
891         if ((status & action) != 0 && (error & (action >> IIM_ERR_SHIFT)) == 0) {
892                 if (error) {
893                         diag_printf("Even though the operation seems successful...\n");
894                         diag_printf("There are some error(s) at addr=0x%08lx: 0x%08x\n",
895                                                 (IIM_BASE_ADDR + IIM_ERR_OFF), error);
896                 }
897                 return 0;
898         }
899         diag_printf("%s(%d) failed\n", __FUNCTION__, action);
900         diag_printf("status address=0x%08lx, value=0x%08x\n",
901                                 (IIM_BASE_ADDR + IIM_STAT_OFF), status);
902         diag_printf("There are some error(s) at addr=0x%08lx: 0x%08x\n",
903                                 (IIM_BASE_ADDR + IIM_ERR_OFF), error);
904         return -1;
905 }
906
907 static void sense_fuse(int bank, int row, int bit)
908 {
909         int ret;
910         int addr, addr_l, addr_h, reg_addr;
911
912         fuse_op_start();
913
914         addr = ((bank << 11) | (row << 3) | (bit & 0x7));
915         /* Set IIM Program Upper Address */
916         addr_h = (addr >> 8) & 0x000000FF;
917         /* Set IIM Program Lower Address */
918         addr_l = (addr & 0x000000FF);
919
920 #ifdef IIM_FUSE_DEBUG
921         diag_printf("%s: addr_h=0x%02x, addr_l=0x%02x\n",
922                                 __FUNCTION__, addr_h, addr_l);
923 #endif
924         writel(addr_h, IIM_BASE_ADDR + IIM_UA_OFF);
925         writel(addr_l, IIM_BASE_ADDR + IIM_LA_OFF);
926         /* Start sensing */
927         writel(0x8, IIM_BASE_ADDR + IIM_FCTL_OFF);
928         if ((ret = poll_fuse_op_done(POLL_FUSE_SNSD)) != 0) {
929                 diag_printf("%s(bank: %d, row: %d, bit: %d failed\n",
930                                         __FUNCTION__, bank, row, bit);
931         }
932         reg_addr = IIM_BASE_ADDR + IIM_SDAT_OFF;
933         if (ret == 0)
934                 diag_printf("fuses at (bank:%d, row:%d) = 0x%02x\n", bank, row, readl(reg_addr));
935 }
936
937 void do_fuse_read(int argc, char *argv[])
938 {
939         unsigned long bank, row;
940
941         if (argc == 1) {
942                 diag_printf("Usage: fuse_read <bank> <row>\n");
943                 return;
944         } else if (argc == 3) {
945                 if (!parse_num(argv[1], &bank, &argv[1], " ")) {
946                         diag_printf("Error: Invalid parameter\n");
947                         return;
948                 }
949                 if (!parse_num(argv[2], &row, &argv[2], " ")) {
950                         diag_printf("Error: Invalid parameter\n");
951                         return;
952                 }
953
954                 diag_printf("Read fuse at bank:%ld row:%ld\n", bank, row);
955                 sense_fuse(bank, row, 0);
956
957         } else {
958                 diag_printf("Passing in wrong arguments: %d\n", argc);
959                 diag_printf("Usage: fuse_read <bank> <row>\n");
960         }
961 }
962
963 /* Blow fuses based on the bank, row and bit positions (all 0-based)
964 */
965 int fuse_blow(int bank, int row, int bit)
966 {
967         int addr, addr_l, addr_h, ret = -1;
968
969         fuse_op_start();
970
971         /* Disable IIM Program Protect */
972         writel(0xAA, IIM_BASE_ADDR + IIM_PREG_P_OFF);
973
974         addr = ((bank << 11) | (row << 3) | (bit & 0x7));
975         /* Set IIM Program Upper Address */
976         addr_h = (addr >> 8) & 0x000000FF;
977         /* Set IIM Program Lower Address */
978         addr_l = (addr & 0x000000FF);
979
980         diag_printf("blowing fuse bank %d row %d bit %d\n", bank, row, bit & 7);
981 #ifdef IIM_FUSE_DEBUG
982         diag_printf("blowing addr_h=0x%02x, addr_l=0x%02x\n", addr_h, addr_l);
983 #endif
984
985         writel(addr_h, IIM_BASE_ADDR + IIM_UA_OFF);
986         writel(addr_l, IIM_BASE_ADDR + IIM_LA_OFF);
987         /* Start Programming */
988         writel(0x71, IIM_BASE_ADDR + IIM_FCTL_OFF);
989         if (poll_fuse_op_done(POLL_FUSE_PRGD) == 0) {
990                 ret = 0;
991         }
992
993         /* Enable IIM Program Protect */
994         writel(0x0, IIM_BASE_ADDR + IIM_PREG_P_OFF);
995         return ret;
996 }
997
998 /*
999  * This command is added for burning IIM fuses
1000  */
1001 RedBoot_cmd("fuse_read",
1002                         "read some fuses",
1003                         "<bank> <row>",
1004                         do_fuse_read
1005         );
1006
1007 RedBoot_cmd("fuse_blow",
1008                         "blow some fuses",
1009                         "<bank> <row> <value>",
1010                         do_fuse_blow
1011         );
1012
1013 #define                 INIT_STRING                              "12345678"
1014 static char ready_to_blow[] = INIT_STRING;
1015
1016 void do_fuse_blow(int argc, char *argv[])
1017 {
1018         unsigned long bank, row, value;
1019         int i;
1020
1021         if (argc == 1) {
1022                 diag_printf("It is too dangeous for you to use this command.\n");
1023                 return;
1024         } else if (argc == 2) {
1025                 if (strcasecmp(argv[1], "nandboot") == 0) {
1026                         diag_printf("%s\n", "fuse blown not needed");
1027                 }
1028                 return;
1029         } else if (argc == 3) {
1030                 if (strcasecmp(argv[1], "nandboot") == 0) {
1031 #if defined(CYGPKG_HAL_ARM_MXC91131) || defined(CYGPKG_HAL_ARM_MX21) || defined(CYGPKG_HAL_ARM_MX27) || defined(CYGPKG_HAL_ARM_MX31)
1032                         diag_printf("No need to blow any fuses for NAND boot on this platform\n");
1033 #else
1034                         diag_printf("Ready to burn NAND boot fuses\n");
1035                         if (fuse_blow(0, 16, 1) != 0 || fuse_blow(0, 16, 7) != 0) {
1036                                 diag_printf("NAND BOOT fuse blown failed miserably ...\n");
1037                         } else {
1038                                 diag_printf("NAND BOOT fuse blown successfully ...\n");
1039                         }
1040                 } else {
1041                         diag_printf("Not ready: %s, %s\n", argv[1], argv[2]);
1042 #endif
1043                 }
1044         } else if (argc == 4) {
1045                 if (!parse_num(argv[1], &bank, &argv[1], " ")) {
1046                         diag_printf("Error: Invalid fuse bank\n");
1047                         return;
1048                 }
1049                 if (!parse_num(argv[2], &row, &argv[2], " ")) {
1050                         diag_printf("Error: Invalid fuse row\n");
1051                         return;
1052                 }
1053                 if (!parse_num(argv[3], &value, &argv[3], " ")) {
1054                         diag_printf("Error: Invalid value\n");
1055                         return;
1056                 }
1057
1058                 if (!verify_action("Confirm to blow fuse at bank:%ld row:%ld value:0x%02lx (%ld)",
1059                                                         bank, row, value)) {
1060                         diag_printf("fuse_blow canceled\n");
1061                         return;
1062                 }
1063
1064                 for (i = 0; i < 8; i++) {
1065                         if (((value >> i) & 0x1) == 0) {
1066                                 continue;
1067                         }
1068                         if (fuse_blow(bank, row, i) != 0) {
1069                                 diag_printf("fuse_blow(bank: %ld, row: %ld, bit: %d failed\n",
1070                                                         bank, row, i);
1071                         } else {
1072                                 diag_printf("fuse_blow(bank: %ld, row: %ld, bit: %d successful\n",
1073                                                         bank, row, i);
1074                         }
1075                 }
1076                 sense_fuse(bank, row, 0);
1077         } else {
1078                 diag_printf("Passing in wrong arguments: %d\n", argc);
1079         }
1080         /* Reset to default string */
1081         strcpy(ready_to_blow, INIT_STRING);
1082 }
1083
1084 /* precondition: m>0 and n>0.  Let g=gcd(m,n). */
1085 int gcd(int m, int n)
1086 {
1087         int t;
1088         while (m > 0) {
1089                 if (n > m) {t = m; m = n; n = t;} /* swap */
1090                 m -= n;
1091         }
1092         return n;
1093 }
1094
1095 #define CLOCK_SRC_DETECT_MS         100
1096 #define CLOCK_IPG_DEFAULT           66500000
1097 #define CLOCK_SRC_DETECT_MARGIN     500000
1098 void mxc_show_clk_input(void)
1099 {
1100 #if 0
1101         u32 c1, c2, diff, ipg_real, num = 0;
1102         u32 prcs = (readl(CCM_BASE_ADDR + CLKCTL_CCMR) >> 1) & 0x3;
1103
1104         return;  // FIXME
1105
1106         switch (prcs) {
1107         case 0x01:
1108                 diag_printf("FPM enabled --> 32KHz input source\n");
1109                 return;
1110         case 0x02:
1111                 break;
1112         default:
1113                 diag_printf("Error %d: unknown clock source %d\n", __LINE__, prcs);
1114                 return;
1115         }
1116
1117         // enable GPT with IPG clock input
1118         writel(0x241, GPT_BASE_ADDR + GPTCR);
1119         // prescaler = 1
1120         writel(0, GPT_BASE_ADDR + GPTPR);
1121
1122         c1 = readl(GPT_BASE_ADDR + GPTCNT);
1123         // use 32KHz input clock to get the delay
1124         hal_delay_us(CLOCK_SRC_DETECT_MS * 1000);
1125         c2 = readl(GPT_BASE_ADDR + GPTCNT);
1126         diff = (c2 > c1) ? (c2 - c1) : (0xFFFFFFFF - c1 + c2);
1127
1128         ipg_real = diff * (1000 / CLOCK_SRC_DETECT_MS);
1129
1130         if (ipg_real > (CLOCK_IPG_DEFAULT + CLOCK_SRC_DETECT_MARGIN)) {
1131                 if (g_clock_src != FREQ_27MHZ)
1132                         num = 27;
1133         } else if (ipg_real < (CLOCK_IPG_DEFAULT - CLOCK_SRC_DETECT_MARGIN)) {
1134                 if (g_clock_src != FREQ_26MHZ)
1135                         num = 26;
1136         }
1137         if (num != 0) {
1138                 diag_printf("Error: Actual clock input is %d MHz\n", num);
1139                 diag_printf("       ipg_real=%d CLOCK_IPG_DEFAULT - CLOCK_SRC_DETECT_MARGIN=%d\n",
1140                                         ipg_real, CLOCK_IPG_DEFAULT - CLOCK_SRC_DETECT_MARGIN);
1141                 diag_printf("       But clock source defined to be %d\n", g_clock_src);
1142                 hal_delay_us(2000000);
1143         } else {
1144                 diag_printf("ipg_real=%d CLOCK_IPG_DEFAULT - CLOCK_SRC_DETECT_MARGIN=%d\n",
1145                                         ipg_real, CLOCK_IPG_DEFAULT - CLOCK_SRC_DETECT_MARGIN);
1146                 diag_printf("clock source defined to be %d\n", g_clock_src);
1147         }
1148 #endif
1149 }
1150
1151 RedBoot_init(mxc_show_clk_input, RedBoot_INIT_LAST);
1152
1153 void clock_spi_enable(unsigned int spi_clk)
1154 {
1155     unsigned int reg = readl(SOC_CRM_PCCR1);
1156
1157     // turn on PERCLK2
1158     writel(reg | (1 << 9), SOC_CRM_PCCR1);
1159
1160     reg = readl(SOC_CRM_PCCR0);
1161
1162     if (spi_clk == SPI1_CLK) {
1163         writel(reg | (1 << 31), SOC_CRM_PCCR0);
1164         gpio_request_mux(MX27_PIN_CSPI1_MOSI, GPIO_MUX_PRIMARY);
1165         gpio_request_mux(MX27_PIN_CSPI1_MISO, GPIO_MUX_PRIMARY);
1166         gpio_request_mux(MX27_PIN_CSPI1_SCLK, GPIO_MUX_PRIMARY);
1167         gpio_request_mux(MX27_PIN_CSPI1_RDY, GPIO_MUX_PRIMARY);
1168         gpio_request_mux(MX27_PIN_CSPI1_SS0, GPIO_MUX_PRIMARY);
1169         gpio_request_mux(MX27_PIN_CSPI1_SS1, GPIO_MUX_PRIMARY);
1170         gpio_request_mux(MX27_PIN_CSPI1_SS2, GPIO_MUX_PRIMARY);
1171     } else if (spi_clk == SPI2_CLK) {
1172         writel(reg | (1 << 30), SOC_CRM_PCCR0);
1173     }
1174 }