]> git.karo-electronics.de Git - karo-tx-redboot.git/blob - packages/hal/arm/mxc91311/var/v2_0/src/cmds.c
Initial revision
[karo-tx-redboot.git] / packages / hal / arm / mxc91311 / 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   390000000
72 #define PLL_FREQ_MIN    ((2 * PLL_REF_CLK * (PLL_MFI_MIN - 1)) / PLL_PD_MAX)
73 #define AHB_CLK_MAX     133000000
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
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
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("UART2/3/4\tSSI1\t\tCSI\n");
383     diag_printf("===========================================\n");
384
385     diag_printf("%-16d%-16d%-16d\n\n",
386                 get_peri_clock(UART2_BAUD),
387                 get_peri_clock(SSI1_BAUD),
388                 get_peri_clock(CSI_BAUD));
389 }
390
391 /*!
392  * This function returns the PLL output value in Hz based on pll.
393  */
394 u32 pll_clock(enum plls pll)
395 {
396     u64 mfi, mfn, mfd, pdf, ref_clk, pll_out, sign;
397     u64 reg = readl(pll);
398
399     pdf = (reg >> 26) & 0xF;
400     mfd = (reg >> 16) & 0x3FF;
401     if (pll == MCU_PLL || pll == TUR_PLL) {
402         mfi = (reg >> 11) & 0xF;
403         mfi = (mfi <= 5) ? 5: mfi;
404         mfn = reg & 0x7FF;
405         sign = (mfn < 1024) ? 0: 1;
406         mfn = (mfn <= 0x400) ? mfn: (0x800 - mfn);
407     } else {
408         sign = 0;
409         mfi = (reg >> 10) & 0xF;
410         mfi = (mfi <= 5) ? 5: mfi;
411         mfn = reg & 0x3FF;
412     }
413
414     /* Scale down to avoid overflow */
415     ref_clk = PLL_REF_CLK;
416     if (ref_clk == 0) {
417         diag_printf("Error: fix input clock first for %s() to work\n",
418                     __FUNCTION__);
419         return 0;
420     }
421
422     if (sign == 0) {
423         pll_out = (2 * ref_clk * mfi + ((2 * ref_clk * mfn) / (mfd + 1))) /
424                   (pdf + 1);
425     } else {
426         pll_out = (2 * ref_clk * mfi - ((2 * ref_clk * mfn) / (mfd + 1))) /
427                   (pdf + 1);
428     }
429
430     return (u32)pll_out;
431 }
432
433 #define NORMALIZE_FACTOR    10
434
435 void clock_spi_enable(unsigned int spi_clk)
436 {
437     if (spi_clk == SPI1_CLK) {
438         // do nothing now as it is already enabled by default
439     }
440 }
441
442 /*!
443  * This function returns the main clock value in Hz.
444  */
445 u32 get_main_clock(enum main_clocks clk)
446 {
447     u32 brmm, max_pdf, ipg_pdf, nfc_pdf, csi_pdf;
448     u32 pll, ret_val = 0, hclk, usb_pdf, div;
449     enum plls CORE_PLL_SEL = MCU_PLL;
450
451     volatile u32 reg = readl(CRM_MCU_BASE_ADDR + CLKCTL_PDR0);
452     volatile u32 reg1 = readl(CRM_MCU_BASE_ADDR + CLKCTL_PDR1);
453     brmm = reg & 0x7;
454     max_pdf = (reg >> 3) & 0x7;
455     ipg_pdf = (reg >> 6) & 0x3;
456     nfc_pdf = (reg >> 8) & 0x7;
457     csi_pdf = reg >> 23;
458     usb_pdf = (reg1 >> 27) & 0x7;
459
460     if ((readl(CRM_MCU_BASE_ADDR + CLKCTL_PDR0) & (1 << 11)) != 0) {
461         CORE_PLL_SEL = TUR_PLL;
462     }
463
464     switch (clk) {
465     case CPU_CLK:
466         pll = pll_clock(CORE_PLL_SEL);
467         if (brmm >= 5) {
468             diag_printf("Wrong BRMM value in the CRM_AP, MPDR0 reg \n");
469             return 0;
470         }
471         hclk = pll / (max_pdf + 1);
472         div = (pll * NORMALIZE_FACTOR) / hclk;
473         switch (brmm) {
474         case 0:
475             ret_val = pll;
476             break;
477         case 1:
478             // new period = (2*MCU_period + 1*AHB_period)/3
479             // => new freq = (3*pll*hclk)/(2*hclk+pll)
480             // => new frq = (3*pll)/(2+pll/hclk). Also normalize it.
481             ret_val = (3* pll * NORMALIZE_FACTOR) /
482                 ((2 * NORMALIZE_FACTOR) + ((pll * NORMALIZE_FACTOR) / hclk));
483             break;
484         case 2:
485             // new period = (1*MCU_period + 1*AHB_period)/2
486             // => new freq = (2*pll*hclk)/(hclk+pll)
487             // => new frq = (2*pll)/(1+pll/hclk). Also normalize it.
488             ret_val = (2* pll * NORMALIZE_FACTOR) /
489                 ((1 * NORMALIZE_FACTOR) + ((pll * NORMALIZE_FACTOR) / hclk));
490             break;
491         case 3:
492             // new period = (1*MCU_period + 2*AHB_period)/3
493             // => new freq = (3*pll*hclk)/(hclk+2*pll)
494             // => new frq = (3*pll)/(1+(2*pll)/hclk). Also normalize it.
495             ret_val = (3* pll * NORMALIZE_FACTOR) /
496                 ((1 * NORMALIZE_FACTOR) + ((2 * pll * NORMALIZE_FACTOR) / hclk));
497             break;
498         case 4:
499             ret_val = hclk;
500             break;
501         default:
502             break;
503         }
504         break;
505     case AHB_CLK:
506         pll = pll_clock(CORE_PLL_SEL);
507         ret_val = pll / (max_pdf + 1);
508         break;
509     case IPG_CLK:
510         pll = pll_clock(CORE_PLL_SEL);
511         ret_val = pll / ((max_pdf + 1) * (ipg_pdf + 1));
512         break;
513     case NFC_CLK:
514         pll = pll_clock(CORE_PLL_SEL);
515         ret_val = pll / ((max_pdf + 1) * (nfc_pdf + 1));
516         break;
517     case USB_CLK:
518         pll = pll_clock(USB_PLL);
519         ret_val = pll / (usb_pdf + 1);
520         break;
521     default:
522         diag_printf("%s(): This clock: %d not supported yet \n",
523                     __FUNCTION__, clk);
524         break;
525     }
526
527     return ret_val;
528 }
529
530 static u32 csi_sdhc_clock_src(u32 clksrc)
531 {
532     u32 val = 0;
533
534     switch (clksrc) {
535     case 0:
536         val = pll_clock(USB_PLL);
537         break;
538     case 1:
539         val = pll_clock(MCU_PLL);
540         break;
541     case 2:
542         val = pll_clock(TUR_PLL);
543         break;
544     case 3:
545         val = FREQ_26MHZ;
546         break;
547     }
548
549     return val;
550 }
551
552 /*!
553  * This function returns the peripheral clock value in Hz.
554  */
555 u32 get_peri_clock(enum peri_clocks clk)
556 {
557     volatile u32 mcr = readl(CRM_MCU_BASE_ADDR + CLKCTL_MCR);
558     volatile u32 mpdr0 = readl(CRM_MCU_BASE_ADDR + CLKCTL_PDR0);
559     volatile u32 mpdr1 = readl(CRM_MCU_BASE_ADDR + CLKCTL_PDR1);
560     u32 clk_sel, pre_pdf, pdf, ref_clk, ret_val = 0;
561
562     switch (clk) {
563     case UART2_BAUD:
564     case UART3_BAUD:
565     case UART4_BAUD:
566         return get_main_clock(IPG_CLK);
567         break;
568     case SSI1_BAUD:
569         pre_pdf = (mpdr1 >> 6) & 0x7;
570         pdf = (mpdr1 >> 1) & 0x1F;
571         clk_sel = mcr & (1 << 28);
572         ref_clk = (clk_sel != 0) ? pll_clock(USB_PLL) : pll_clock(MCU_PLL);
573         ret_val = ref_clk / ((pre_pdf + 1) * (pdf + 1));
574         break;
575     case CSI_BAUD:
576         clk_sel = (mcr >> 25) & 0x3;
577         pdf = ((mpdr0 >> 23) & 0x1FF) + 1;
578         pdf = (2 * pdf) + (mpdr0 & (1 << 22)); //multiplied by 2
579         pdf *= (1 + (mpdr0 & (1 << 21)));
580
581         ret_val = (2 * csi_sdhc_clock_src(clk_sel)) / pdf;
582         break;
583     case SPI1_CLK:
584     case SPI2_CLK:
585         ret_val = get_main_clock(IPG_CLK);
586         break;
587     default:
588         diag_printf("%s(): This clock: %d not supported yet \n",
589                     __FUNCTION__, clk);
590         break;
591     }
592
593     return ret_val;
594 }
595
596 RedBoot_cmd("ckol",
597             "Select clock source for CKO1 (AKA CKO) (J10 on the EVB CPU daughter card)",
598             " The output is 1/8 of actual clock. Default is MCU_PLL\n\
599           <0> - display current cko selection\n\
600           <1> - MCU_PLL \n\
601           <2> - CKIH \n\
602           <3> - USB_PLL \n\
603           <4} - DSP_PLL \n\
604           <5> - WB_PAT_REF \n\
605           <6> - RESERVED \n\
606           <7> - RESERVED \n\
607           <8> - MB_PAT_REF \n",
608             ckol
609            );
610
611 static u8* cko_name[] = {
612     "NULL",
613     "MCU_PLL",
614     "CKIH",
615     "USB_PLL",
616     "DSP_PLL",
617     "WB_PAT_REF",
618     "RESERVED",
619     "RESERVED",
620     "MB_PAT_REF",
621 };
622
623 #define CKO_MAX_INDEX           (sizeof(cko_name) / sizeof(u8*))
624 #define CKO_DIV                 3  // default divide by 8
625 #define CKOH_DIV                3  // default divide by 8
626
627 static void ckol(int argc,char *argv[])
628 {
629     u32 action = 0, cosr;
630
631     if (!scan_opts(argc, argv, 1, 0, 0, (void*) &action,
632                    OPTION_ARG_TYPE_NUM, "action"))
633         return;
634
635     if (action >= CKO_MAX_INDEX) {
636         diag_printf("%d is not supported\n\n", action);
637         return;
638     }
639
640     cosr = readl(CRM_MCU_BASE_ADDR + CLKCTL_COSR);
641
642     if (action != 0) {
643         cosr = (cosr & (~0x7F)) + (1 << 6) + (CKO_DIV << 3) + action - 1;
644         writel(cosr, CRM_MCU_BASE_ADDR + CLKCTL_COSR);
645         diag_printf("Set clko to ");
646     }
647
648     cosr = readl(CRM_MCU_BASE_ADDR + CLKCTL_COSR);
649     diag_printf("%s\n", cko_name[(cosr & 0x7) + 1]);
650     diag_printf("COSR register[0x%x] = 0x%x\n",
651                 (CRM_MCU_BASE_ADDR + CLKCTL_COSR), cosr);
652 }
653
654 RedBoot_cmd("ckoh",
655             "Select clock source for CKO2 (J9 on the EVB CPU daughter card)",
656             " The default is 1/8 of IPG_CLK_ARM (core clock)\n\
657           <0> - display current cko selection\n\
658           <1> - MCU_PLL \n\
659           <2> - REC_64KHZ \n\
660           <3> - USB_PLL \n\
661           <4} - DSP_PLL \n\
662           <5> - WB_PLL \n\
663           <6> - RESERVED \n\
664           <7> - RESERVED \n\
665           <8> - WCSI_RX \n\
666           <9> - NFC_CLK \n\
667           <10> - MCU_AHB_CLK \n\
668           <11> - IPG_CLK_S \n\
669           <12> - IPG_CLK \n\
670           <13> - DSP_AHB_CLK \n\
671           <14> - IPG_CLK_ARM (Core) \n\
672           <15> - PAT_REF_CLK_SYNC \n\
673           <16> - WB_PAT_REF_CLK_SYNC \n\
674           <17> - TURBO_PLL\n\
675           <18> - AFC_PLL \n",
676             ckoh
677            );
678
679 static u8* div_str[] = {
680     "original ",
681     "1/2 of ",
682     "1/4 of ",
683     "1/8 of ",
684     "1/16 of ",
685     "unknown of ",
686     "unknown of ",
687     "unknown of ",
688 };
689
690 static u8* ckoh_name[] ={
691     "NULL",
692     "MCU_PLL",
693     "REC_64KHZ",
694     "USB_PLL",
695     "DSP_PLL",
696     "WB_PLL",
697     "RESERVED",
698     "RESERVED",
699     "WCSI_RX",
700     "NFC_CLK",
701     "MCU_AHB_CLK",
702     "IPG_CLK_S",
703     "IPG_CLK",
704     "DSP_AHB_CLK",
705     "IPG_CLK_ARM (Core)",
706     "PAT_REF_CLK_SYNC",
707     "WB_PAT_REF_CLK_SYNC",
708     "TURBO_PLL",
709     "AFC_PLL",
710 };
711
712 #define CKOH_MAX_INDEX           (sizeof(ckoh_name) / sizeof(u8*))
713
714 static void ckoh(int argc,char *argv[])
715 {
716     u32 action = 0, cosr, div = 0, i, j;
717
718     if (!scan_opts(argc, argv, 1, 0, 0, (void*) &action,
719                    OPTION_ARG_TYPE_NUM, "action"))
720         return;
721
722     if (action >= CKOH_MAX_INDEX) {
723         diag_printf("%d is not supported\n\n", action);
724         return;
725     }
726
727     cosr = readl(CRM_MCU_BASE_ADDR + CLKCTL_COSR);
728
729     if (action != 0) {
730         if (action == 1 || action == 3 || action == 4 || action == 5 || action == 14 || action == 17)
731             div = CKOH_DIV;
732         cosr = (cosr & (~0x0007FC00)) + (div << 10) + (1 << 13) +
733                ((action - 1) << 14);
734         writel(cosr, CRM_MCU_BASE_ADDR + CLKCTL_COSR);
735         diag_printf("Set clko to ");
736     }
737
738     cosr = readl(CRM_MCU_BASE_ADDR + CLKCTL_COSR);
739     i = (cosr >> 10) & 0x7;
740     j = (cosr >> 14) & 0x1F;
741     diag_printf("%s%s\n", div_str[i], ckoh_name[j + 1]);
742     diag_printf("COSR register[0x%x] = 0x%x\n",
743                 (CRM_MCU_BASE_ADDR + CLKCTL_COSR), cosr);
744 }
745
746 #define IIM_ERR_SHIFT       8
747 #define POLL_FUSE_PRGD      (IIM_STAT_PRGD | (IIM_ERR_PRGE << IIM_ERR_SHIFT))
748 #define POLL_FUSE_SNSD      (IIM_STAT_SNSD | (IIM_ERR_SNSE << IIM_ERR_SHIFT))
749
750 static void fuse_op_start(void)
751 {
752     /* Do not generate interrupt */
753     writel(0, IIM_BASE_ADDR + IIM_STATM_OFF);
754     // clear the status bits and error bits
755     writel(0x3, IIM_BASE_ADDR + IIM_STAT_OFF);
756     writel(0xFE, IIM_BASE_ADDR + IIM_ERR_OFF);
757 }
758
759 /*
760  * The action should be either:
761  *          POLL_FUSE_PRGD
762  * or:
763  *          POLL_FUSE_SNSD
764  */
765 static int poll_fuse_op_done(int action)
766 {
767
768     u32 status, error;
769
770     if (action != POLL_FUSE_PRGD && action != POLL_FUSE_SNSD) {
771         diag_printf("%s(%d) invalid operation\n", __FUNCTION__, action);
772         return -1;
773     }
774
775     /* Poll busy bit till it is NOT set */
776     while ((readl(IIM_BASE_ADDR + IIM_STAT_OFF) & IIM_STAT_BUSY) != 0 ) {
777     }
778
779     /* Test for successful write */
780     status = readl(IIM_BASE_ADDR + IIM_STAT_OFF);
781     error = readl(IIM_BASE_ADDR + IIM_ERR_OFF);
782
783     if ((status & action) != 0 && (error & (action >> IIM_ERR_SHIFT)) == 0) {
784         if (error) {
785             diag_printf("Even though the operation seems successful...\n");
786             diag_printf("There are some error(s) at addr=0x%x: 0x%x\n",
787                         (IIM_BASE_ADDR + IIM_ERR_OFF), error);
788         }
789         return 0;
790     }
791     diag_printf("%s(%d) failed\n", __FUNCTION__, action);
792     diag_printf("status address=0x%x, value=0x%x\n",
793                 (IIM_BASE_ADDR + IIM_STAT_OFF), status);
794     diag_printf("There are some error(s) at addr=0x%x: 0x%x\n",
795                 (IIM_BASE_ADDR + IIM_ERR_OFF), error);
796     return -1;
797 }
798
799 unsigned int sense_fuse(int bank, int row, int bit)
800 {
801     int addr, addr_l, addr_h, reg_addr;
802
803     fuse_op_start();
804
805     addr = ((bank << 11) | (row << 3) | (bit & 0x7));
806     /* Set IIM Program Upper Address */
807     addr_h = (addr >> 8) & 0x000000FF;
808     /* Set IIM Program Lower Address */
809     addr_l = (addr & 0x000000FF);
810
811 #ifdef IIM_FUSE_DEBUG
812     diag_printf("%s: addr_h=0x%x, addr_l=0x%x\n",
813                 __FUNCTION__, addr_h, addr_l);
814 #endif
815     writel(addr_h, IIM_BASE_ADDR + IIM_UA_OFF);
816     writel(addr_l, IIM_BASE_ADDR + IIM_LA_OFF);
817     /* Start sensing */
818     writel(0x8, IIM_BASE_ADDR + IIM_FCTL_OFF);
819     if (poll_fuse_op_done(POLL_FUSE_SNSD) != 0) {
820         diag_printf("%s(bank: %d, row: %d, bit: %d failed\n",
821                     __FUNCTION__, bank, row, bit);
822     }
823     reg_addr = IIM_BASE_ADDR + IIM_SDAT_OFF;
824     diag_printf("fuses at (bank:%d, row:%d) = 0x%x\n", bank, row, readl(reg_addr));
825
826     return readl(reg_addr);
827 }
828
829 void do_fuse_read(int argc, char *argv[])
830 {
831     int bank, row;
832
833     if (argc == 1) {
834         diag_printf("Useage: fuse_read <bank> <row>\n");
835         return;
836     } else if (argc == 3) {
837         if (!parse_num(*(&argv[1]), (unsigned long *)&bank, &argv[1], " ")) {
838                 diag_printf("Error: Invalid parameter\n");
839             return;
840         }
841         if (!parse_num(*(&argv[2]), (unsigned long *)&row, &argv[2], " ")) {
842                 diag_printf("Error: Invalid parameter\n");
843                 return;
844             }
845
846         diag_printf("Read fuse at bank:%d row:%d\n", bank, row);
847         sense_fuse(bank, row, 0);
848
849     } else {
850         diag_printf("Passing in wrong arguments: %d\n", argc);
851         diag_printf("Useage: fuse_read <bank> <row>\n");
852     }
853 }
854
855 /* Blow fuses based on the bank, row and bit positions (all 0-based)
856 */
857 static int fuse_blow(int bank,int row,int bit)
858 {
859     int addr, addr_l, addr_h, ret = -1;
860
861     fuse_op_start();
862
863     /* Disable IIM Program Protect */
864     writel(0xAA, IIM_BASE_ADDR + IIM_PREG_P_OFF);
865
866     addr = ((bank << 11) | (row << 3) | (bit & 0x7));
867     /* Set IIM Program Upper Address */
868     addr_h = (addr >> 8) & 0x000000FF;
869     /* Set IIM Program Lower Address */
870     addr_l = (addr & 0x000000FF);
871
872 #ifdef IIM_FUSE_DEBUG
873     diag_printf("blowing addr_h=0x%x, addr_l=0x%x\n", addr_h, addr_l);
874 #endif
875
876     writel(addr_h, IIM_BASE_ADDR + IIM_UA_OFF);
877     writel(addr_l, IIM_BASE_ADDR + IIM_LA_OFF);
878     /* Start Programming */
879     writel(0x31, IIM_BASE_ADDR + IIM_FCTL_OFF);
880     if (poll_fuse_op_done(POLL_FUSE_PRGD) == 0) {
881         ret = 0;
882     }
883
884     /* Enable IIM Program Protect */
885     writel(0x0, IIM_BASE_ADDR + IIM_PREG_P_OFF);
886     return ret;
887 }
888
889 /*
890  * This command is added for burning IIM fuses
891  */
892 RedBoot_cmd("fuse_read",
893             "read some fuses",
894             "<bank> <row>",
895             do_fuse_read
896            );
897
898 RedBoot_cmd("fuse_blow",
899             "blow some fuses",
900             "<bank> <row> <value>",
901             do_fuse_blow
902            );
903
904 #define         INIT_STRING              "12345678"
905 static char ready_to_blow[] = INIT_STRING;
906
907 void quick_itoa(u32 num, char *a)
908 {
909     int i, j, k;
910     for (i = 0; i <= 7; i++) {
911         j = (num >> (4 * i)) & 0xF;
912         k = (j < 10) ? '0' : ('a' - 0xa);
913         a[i] = j + k;
914     }
915 }
916
917 void do_fuse_blow(int argc, char *argv[])
918 {
919     int bank, row, value, i;
920
921     if (argc == 1) {
922         diag_printf("It is too dangeous for you to use this command.\n");
923         return;
924     } else if (argc == 2) {
925         if (strcasecmp(argv[1], "nandboot") == 0) {
926             quick_itoa(readl(EPIT_BASE_ADDR + EPITCNR), ready_to_blow);
927             diag_printf("%s\n", ready_to_blow);
928         }
929         return;
930     } else if (argc == 3) {
931         if (strcasecmp(argv[1], "nandboot") == 0 &&
932             strcasecmp(argv[2], ready_to_blow) == 0) {
933 #if defined(CYGPKG_HAL_ARM_MXC91131) || defined(CYGPKG_HAL_ARM_MX21) || defined(CYGPKG_HAL_ARM_MX27) || defined(CYGPKG_HAL_ARM_MX31)
934             diag_printf("No need to blow any fuses for NAND boot on this platform\n\n");
935 #else
936             diag_printf("Ready to burn NAND boot fuses\n");
937             if (fuse_blow(0, 16, 1) != 0 || fuse_blow(0, 16, 7) != 0) {
938                 diag_printf("NAND BOOT fuse blown failed miserably ...\n");
939             } else {
940                 diag_printf("NAND BOOT fuse blown successfully ...\n");
941             }
942         } else {
943             diag_printf("Not ready: %s, %s\n", argv[1], argv[2]);
944 #endif
945         }
946     } else if (argc == 4) {
947         if (!parse_num(*(&argv[1]), (unsigned long *)&bank, &argv[1], " ")) {
948                 diag_printf("Error: Invalid parameter\n");
949             return;
950         }
951         if (!parse_num(*(&argv[2]), (unsigned long *)&row, &argv[2], " ")) {
952                 diag_printf("Error: Invalid parameter\n");
953                 return;
954         }
955         if (!parse_num(*(&argv[3]), (unsigned long *)&value, &argv[3], " ")) {
956                 diag_printf("Error: Invalid parameter\n");
957                 return;
958         }
959
960         diag_printf("Blowing fuse at bank:%d row:%d value:%d\n",
961                     bank, row, value);
962         for (i = 0; i < 8; i++) {
963             if (((value >> i) & 0x1) == 0) {
964                 continue;
965             }
966             if (fuse_blow(bank, row, i) != 0) {
967                 diag_printf("fuse_blow(bank: %d, row: %d, bit: %d failed\n",
968                             bank, row, i);
969             } else {
970                 diag_printf("fuse_blow(bank: %d, row: %d, bit: %d successful\n",
971                             bank, row, i);
972             }
973         }
974         sense_fuse(bank, row, 0);
975
976     } else {
977         diag_printf("Passing in wrong arguments: %d\n", argc);
978     }
979     /* Reset to default string */
980     strcpy(ready_to_blow, INIT_STRING);;
981 }
982
983 /* precondition: m>0 and n>0.  Let g=gcd(m,n). */
984 int gcd(int m, int n)
985 {
986     int t;
987     while(m > 0) {
988         if(n > m) {t = m; m = n; n = t;} /* swap */
989         m -= n;
990     }
991     return n;
992  }