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