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