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