]> git.kernelconcepts.de Git - karo-tx-redboot.git/blob - packages/hal/arm/mx51/var/v2_0/src/cmds.c
Initial revision
[karo-tx-redboot.git] / packages / hal / arm / mx51 / 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 int gcd(int m, int n);
48
49 typedef unsigned long long  u64;
50 typedef unsigned int        u32;
51 typedef unsigned short      u16;
52 typedef unsigned char       u8;
53
54 #define SZ_DEC_1M       1000000
55 #define PLL_PD_MAX      16      //actual pd+1
56 #define PLL_MFI_MAX     15
57 #define PLL_MFI_MIN     5
58 #define ARM_DIV_MAX     8
59 #define IPG_DIV_MAX     4
60 #define AHB_DIV_MAX     8
61 #define EMI_DIV_MAX     8
62 #define NFC_DIV_MAX     8
63
64 #define REF_IN_CLK_NUM  4
65 struct fixed_pll_mfd {
66     u32 ref_clk_hz;
67     u32 mfd;
68 };
69 const struct fixed_pll_mfd fixed_mfd[REF_IN_CLK_NUM] = {
70     {0,                   0},      // reserved
71     {0,                   0},      // reserved
72     {FREQ_24MHZ,          24 * 16},    // 384
73     {0,                   0},      // reserved
74 };
75
76 struct pll_param {
77     u32 pd;
78     u32 mfi;
79     u32 mfn;
80     u32 mfd;
81 };
82
83 #define PLL_FREQ_MAX(_ref_clk_)    (4 * _ref_clk_ * PLL_MFI_MAX)
84 #define PLL_FREQ_MIN(_ref_clk_)    ((2 * _ref_clk_ * (PLL_MFI_MIN - 1)) / PLL_PD_MAX)
85 #define MAX_DDR_CLK      200000000
86 #define AHB_CLK_MAX     133333333
87 #define IPG_CLK_MAX     (AHB_CLK_MAX / 2)
88 #define NFC_CLK_MAX     25000000
89 // IPU-HSP clock is independent of the HCLK and can go up to 177MHz but requires
90 // higher voltage support. For simplicity, limit it to 133MHz
91 #define HSP_CLK_MAX     133333333
92
93 #define ERR_WRONG_CLK   -1
94 #define ERR_NO_MFI      -2
95 #define ERR_NO_MFN      -3
96 #define ERR_NO_PD       -4
97 #define ERR_NO_PRESC    -5
98 #define ERR_NO_AHB_DIV  -6
99
100 u32 pll_clock(enum plls pll);
101 u32 get_main_clock(enum main_clocks clk);
102 u32 get_peri_clock(enum peri_clocks clk);
103
104 static volatile u32 *pll_base[] =
105 {
106     REG32_PTR(PLL1_BASE_ADDR),
107     REG32_PTR(PLL2_BASE_ADDR),
108     REG32_PTR(PLL3_BASE_ADDR),
109 };
110
111 #define NOT_ON_VAL  0xDEADBEEF
112
113 static void clock_setup(int argc, char *argv[]);
114
115 RedBoot_cmd("clock",
116             "Setup/Display clock\nSyntax:",
117             "[<core clock in MHz> :<DDR clock in MHz>] \n\n\
118    Examples:\n\
119    [clock]         -> Show various clocks\n\
120    [clock 665]     -> Core=665  \n\
121    [clock 800:133]  -> Core=800  DDR=133 \n\
122    [clock :166]   -> Core=no change  DDR=166 \n",
123             clock_setup
124            );
125
126 /*!
127  * This is to calculate various parameters based on reference clock and
128  * targeted clock based on the equation:
129  *      t_clk = 2*ref_freq*(mfi + mfn/(mfd+1))/(pd+1)
130  * This calculation is based on a fixed MFD value for simplicity.
131  *
132  * @param ref       reference clock freq in Hz
133  * @param target    targeted clock in Hz
134  * @param p_pd      calculated pd value (pd value from register + 1) upon return
135  * @param p_mfi     calculated actual mfi value upon return
136  * @param p_mfn     calculated actual mfn value upon return
137  * @param p_mfd     fixed mfd value (mfd value from register + 1) upon return
138  *
139  * @return          0 if successful; non-zero otherwise.
140  */
141 int calc_pll_params(u32 ref, u32 target, struct pll_param *pll)
142 {
143     u64 pd, mfi = 1, mfn, mfd, n_target = target, n_ref = ref, i;
144
145     // make sure targeted freq is in the valid range. Otherwise the
146     // following calculation might be wrong!!!
147     if (n_target < PLL_FREQ_MIN(ref) || n_target > PLL_FREQ_MAX(ref))
148         return ERR_WRONG_CLK;
149     for (i = 0; ; i++) {
150         if (i == REF_IN_CLK_NUM)
151             return ERR_WRONG_CLK;
152         if (fixed_mfd[i].ref_clk_hz == ref) {
153             mfd = fixed_mfd[i].mfd;
154             break;
155         }
156     }
157
158     // Use n_target and n_ref to avoid overflow
159     for (pd = 1; pd <= PLL_PD_MAX; pd++) {
160         mfi = (n_target * pd) / (4 * n_ref);
161         if (mfi > PLL_MFI_MAX) {
162             return ERR_NO_MFI;
163         } else if (mfi < 5) {
164             continue;
165         }
166         break;
167     }
168     // Now got pd and mfi already
169     mfn = (((n_target * pd) / 4 - n_ref * mfi) * mfd) / n_ref;
170 #ifdef CMD_CLOCK_DEBUG
171     diag_printf("%d: ref=%d, target=%d, pd=%d, mfi=%d,mfn=%d, mfd=%d\n",
172                 __LINE__, ref, (u32)n_target, (u32)pd, (u32)mfi, (u32)mfn, (u32)mfd);
173 #endif
174     i = 1;
175     if (mfn != 0)
176         i = gcd(mfd, mfn);
177     pll->pd = (u32)pd;
178     pll->mfi = (u32)mfi;
179     pll->mfn = (u32)(mfn / i);
180     pll->mfd = (u32)(mfd / i);
181     return 0;
182 }
183
184 /*!
185  * This function returns the low power audio clock.
186  */
187 u32 get_lp_apm(void)
188 {
189     u32 ret_val = 0;
190     u32 ccsr = readl(CCM_BASE_ADDR + CLKCTL_CCSR);
191
192     if (((ccsr >> 9) & 1) == 0) {
193         ret_val = FREQ_24MHZ;
194     } else {
195         ret_val = FREQ_32768HZ;
196     }
197     return ret_val;
198 }
199
200 /*!
201  * This function returns the periph_clk.
202  */
203 u32 get_periph_clk(void)
204 {
205     u32 ret_val = 0, clk_sel;
206
207     u32 cbcdr = readl(CCM_BASE_ADDR + CLKCTL_CBCDR);
208     u32 cbcmr = readl(CCM_BASE_ADDR + CLKCTL_CBCMR);
209
210     if (((cbcdr >> 25) & 1) == 0) {
211         ret_val = pll_clock(PLL2);
212     } else {
213         clk_sel = (cbcmr >> 12) & 3;
214         if (clk_sel == 0) {
215             ret_val = pll_clock(PLL1);
216         } else if (clk_sel == 1) {
217             ret_val = pll_clock(PLL3);
218         } else if (clk_sel == 2) {
219             ret_val = get_lp_apm();
220         }
221     }
222     return ret_val;
223 }
224
225 /*!
226  * This function assumes the expected core clock has to be changed by
227  * modifying the PLL. This is NOT true always but for most of the times,
228  * it is. So it assumes the PLL output freq is the same as the expected
229  * core clock (presc=1) unless the core clock is less than PLL_FREQ_MIN.
230  * In the latter case, it will try to increase the presc value until
231  * (presc*core_clk) is greater than PLL_FREQ_MIN. It then makes call to
232  * calc_pll_params() and obtains the values of PD, MFI,MFN, MFD based
233  * on the targeted PLL and reference input clock to the PLL. Lastly,
234  * it sets the register based on these values along with the dividers.
235  * Note 1) There is no value checking for the passed-in divider values
236  *         so the caller has to make sure those values are sensible.
237  *      2) Also adjust the NFC divider such that the NFC clock doesn't
238  *         exceed NFC_CLK_MAX.
239  *      3) IPU HSP clock is independent of AHB clock. Even it can go up to
240  *         177MHz for higher voltage, this function fixes the max to 133MHz.
241  *      4) This function should not have allowed diag_printf() calls since
242  *         the serial driver has been stoped. But leave then here to allow
243  *         easy debugging by NOT calling the cyg_hal_plf_serial_stop().
244  *
245  * @param ref       pll input reference clock (24MHz)
246  * @param core_clk  core clock in Hz
247  * @param emi_clk   emi clock in Hz
248  # @return          0 if successful; non-zero otherwise
249  */
250 int configure_clock(u32 ref, u32 core_clk, u32 emi_clk)
251 {
252
253     u32 pll, clk_src;
254     struct pll_param pll_param;
255     int ret, clk_sel, div = 1, div_core = 1, div_per = 1, shift = 0;
256     u32 cbcdr = readl(CCM_BASE_ADDR + CLKCTL_CBCDR);
257     u32 cbcmr = readl(CCM_BASE_ADDR + CLKCTL_CBCMR);
258     u32 ccsr = readl(CCM_BASE_ADDR + CLKCTL_CCSR);
259     u32 icgc = readl(PLATFORM_BASE_ADDR + PLATFORM_ICGC);
260
261     if (core_clk != 0) {
262         // assume pll default to core clock first
263         pll = core_clk;
264         if ((ret = calc_pll_params(ref, pll, &pll_param)) != 0) {
265              diag_printf("can't find pll parameters: %d\n", ret);
266              return ret;
267         }
268 #ifdef CMD_CLOCK_DEBUG
269         diag_printf("ref=%d, pll=%d, pd=%d, mfi=%d,mfn=%d, mfd=%d\n",
270                     ref, pll, pll_param.pd, pll_param.mfi, pll_param.mfn, pll_param.mfd);
271 #endif
272
273         /* Applies for TO 2 only */
274         if (((cbcdr >> 30) & 0x1) == 0x1) {
275             /* Disable IPU and HSC dividers */
276             writel(0x60000, CCM_BASE_ADDR + CLKCTL_CCDR);
277             /* Switch DDR to different source */
278             writel(cbcdr & ~0x40000000, CCM_BASE_ADDR + CLKCTL_CBCDR);
279             while (readl(CCM_BASE_ADDR + CLKCTL_CDHIPR) != 0);
280             writel(0x0, CCM_BASE_ADDR + CLKCTL_CCDR);
281         }
282
283         /* Switch ARM to PLL2 clock */
284         writel(ccsr | 0x4, CCM_BASE_ADDR + CLKCTL_CCSR);
285
286         if ((core_clk > 665000000) && (core_clk <= 800000000)) {
287             div_per = 5;
288         } else if (core_clk > 800000000) {
289             div_per = 6;
290         } else {
291             div_per = 4;
292         }
293
294         if (core_clk > 800000000) {
295             div_core = 3;
296             increase_core_voltage(true);
297         } else {
298             div_core = 2;
299             increase_core_voltage(false);
300         }
301
302         // adjust pll settings
303         writel(((pll_param.pd - 1) << 0) | (pll_param.mfi << 4),
304                    PLL1_BASE_ADDR + PLL_DP_OP);
305         writel(pll_param.mfn, PLL1_BASE_ADDR + PLL_DP_MFN);
306         writel(pll_param.mfd - 1, PLL1_BASE_ADDR + PLL_DP_MFD);
307         writel(((pll_param.pd - 1) << 0) | (pll_param.mfi << 4),
308                PLL1_BASE_ADDR + PLL_DP_HFS_OP);
309         writel(pll_param.mfn, PLL1_BASE_ADDR + PLL_DP_HFS_MFN);
310         writel(pll_param.mfd - 1, PLL1_BASE_ADDR + PLL_DP_HFS_MFD);
311
312         icgc &= ~(0x77);
313         icgc |= (div_core << 4);
314         icgc |= div_per;
315         /* Set the platform clock dividers */
316         writel(icgc, PLATFORM_BASE_ADDR + PLATFORM_ICGC);
317         /* Switch ARM back to PLL1 */
318         writel((ccsr & ~0x4), CCM_BASE_ADDR + CLKCTL_CCSR);
319         /* Applies for TO 2 only */
320         if (((cbcdr >> 30) & 0x1) == 0x1) {
321             /* Disable IPU and HSC dividers */
322             writel(0x60000, CCM_BASE_ADDR + CLKCTL_CCDR);
323             /* Switch DDR back to PLL1 */
324             writel(cbcdr | 0x40000000, CCM_BASE_ADDR + CLKCTL_CBCDR);
325             while (readl(CCM_BASE_ADDR + CLKCTL_CDHIPR) != 0);
326             writel(0x0, CCM_BASE_ADDR + CLKCTL_CCDR);
327             if (emi_clk == 0) {
328                 /* Keep EMI clock to the max if not specified */
329                 emi_clk = 200000000;
330             }
331         }
332     }
333
334     if (emi_clk != 0) {
335         /* Applies for TO 2 only */
336         if (((cbcdr >> 30) & 0x1) == 0x1) {
337             clk_src = pll_clock(PLL1);
338             shift = 27;
339         } else {
340             clk_src = get_periph_clk();
341             /* Find DDR clock input */
342             clk_sel = (cbcmr >> 10) & 0x3;
343             if (clk_sel == 0) {
344                 shift = 16;
345             } else if (clk_sel == 1) {
346                 shift = 19;
347             } else if (clk_sel == 2) {
348                 shift = 22;
349             } else if (clk_sel == 3) {
350                 shift = 10;
351             }
352         }
353         if ((clk_src % emi_clk) == 0)
354             div = clk_src / emi_clk;
355         else
356             div = (clk_src / emi_clk) + 1;
357         if (div > 8)
358             div = 8;
359
360         cbcdr = cbcdr & ~(0x7 << shift);
361         cbcdr |= ((div - 1) << shift);
362         /* Disable IPU and HSC dividers */
363         writel(0x60000, CCM_BASE_ADDR + CLKCTL_CCDR);
364         writel(cbcdr, CCM_BASE_ADDR + CLKCTL_CBCDR);
365         while (readl(CCM_BASE_ADDR + CLKCTL_CDHIPR) != 0);
366         writel(0x0, CCM_BASE_ADDR + CLKCTL_CCDR);
367     }
368     return 0;
369 }
370
371 static void clock_setup(int argc,char *argv[])
372 {
373
374     u32 i, core_clk, ddr_clk, data[3];
375     unsigned long temp;
376     int ret;
377
378     if (argc == 1)
379         goto print_clock;
380
381     for (i = 0;  i < 2;  i++) {
382         if (!parse_num(*(&argv[1]), &temp, &argv[1], ":")) {
383             diag_printf("Error: Invalid parameter\n");
384             return;
385         }
386         data[i] = temp;
387     }
388
389     core_clk = data[0] * SZ_DEC_1M;
390     ddr_clk = data[1] *  SZ_DEC_1M;
391
392     if (core_clk != 0) {
393         if ((core_clk < PLL_FREQ_MIN(PLL_REF_CLK)) || (core_clk > PLL_FREQ_MAX(PLL_REF_CLK))) {
394             diag_printf("Targeted core clock should be within [%d - %d]\n",
395                             PLL_FREQ_MIN(PLL_REF_CLK), PLL_FREQ_MAX(PLL_REF_CLK));
396             return;
397         }
398     }
399
400     if (ddr_clk != 0) {
401         if (ddr_clk > MAX_DDR_CLK) {
402             diag_printf("DDR clock should be less than %d MHz, assuming max value \n", (MAX_DDR_CLK / SZ_DEC_1M));
403             ddr_clk = MAX_DDR_CLK;
404         }
405     }
406
407     // stop the serial to be ready to adjust the clock
408     hal_delay_us(100000);
409     cyg_hal_plf_serial_stop();
410     // adjust the clock
411     ret = configure_clock(PLL_REF_CLK, core_clk, ddr_clk);
412     // restart the serial driver
413     cyg_hal_plf_serial_init();
414     hal_delay_us(100000);
415
416     if (ret != 0) {
417         diag_printf("Failed to setup clock: %d\n", ret);
418         return;
419     }
420     diag_printf("\n<<<New clock setting>>>\n");
421
422     // Now printing clocks
423 print_clock:
424
425     diag_printf("\nPLL1\t\tPLL2\t\tPLL3\n");
426     diag_printf("========================================\n");
427     diag_printf("%-16d%-16d%-16d\n\n", pll_clock(PLL1), pll_clock(PLL2),
428                 pll_clock(PLL3));
429     diag_printf("CPU\t\tAHB\t\tIPG\t\tEMI_CLK\n");
430     diag_printf("========================================================\n");
431     diag_printf("%-16d%-16d%-16d%-16d\n\n",
432                 get_main_clock(CPU_CLK),
433                 get_main_clock(AHB_CLK),
434                 get_main_clock(IPG_CLK),
435                 get_main_clock(DDR_CLK));
436
437     diag_printf("NFC\t\tUSB\t\tIPG_PER_CLK\n");
438     diag_printf("========================================\n");
439     diag_printf("%-16d%-16d%-16d\n\n",
440                 get_main_clock(NFC_CLK),
441                 get_main_clock(USB_CLK),
442                 get_main_clock(IPG_PER_CLK));
443
444     diag_printf("UART1-3\t\tSSI1\t\tSSI2\t\tSPI\n");
445     diag_printf("===========================================");
446     diag_printf("=============\n");
447
448     diag_printf("%-16d%-16d%-16d%-16d\n\n",
449                 get_peri_clock(UART1_BAUD),
450                 get_peri_clock(SSI1_BAUD),
451                 get_peri_clock(SSI2_BAUD),
452                 get_peri_clock(SPI1_CLK));
453
454 #if 0
455     diag_printf("IPG_PERCLK as baud clock for: UART1-5, I2C, OWIRE, SDHC");
456     if (((readl(EPIT1_BASE_ADDR) >> 24) & 0x3) == 0x2) {
457         diag_printf(", EPIT");
458     }
459     if (((readl(GPT1_BASE_ADDR) >> 6) & 0x7) == 0x2) {
460         diag_printf("GPT,");
461     }
462 #endif
463     diag_printf("\n");
464
465 }
466
467 /*!
468  * This function returns the PLL output value in Hz based on pll.
469  */
470 u32 pll_clock(enum plls pll)
471 {
472     u64 mfi, mfn, mfd, pdf, ref_clk, pll_out, sign;
473     u64 dp_ctrl, dp_op, dp_mfd, dp_mfn, clk_sel;
474     u8 dbl = 0;
475
476     dp_ctrl = pll_base[pll][PLL_DP_CTL >> 2];
477     clk_sel = MXC_GET_FIELD(dp_ctrl, 2, 8);
478     ref_clk = fixed_mfd[clk_sel].ref_clk_hz;
479
480     if ((pll_base[pll][PLL_DP_CTL >> 2] & 0x80) == 0) {
481         dp_op = pll_base[pll][PLL_DP_OP >> 2];
482         dp_mfd = pll_base[pll][PLL_DP_MFD >> 2];
483         dp_mfn = pll_base[pll][PLL_DP_MFN >> 2];
484     } else {
485         dp_op = pll_base[pll][PLL_DP_HFS_OP >> 2];
486         dp_mfd = pll_base[pll][PLL_DP_HFS_MFD >> 2];
487         dp_mfn = pll_base[pll][PLL_DP_HFS_MFN >> 2];
488     }
489     pdf = dp_op & 0xF;
490     mfi = (dp_op >> 4) & 0xF;
491     mfi = (mfi <= 5) ? 5: mfi;
492     mfd = dp_mfd & 0x07FFFFFF;
493     mfn = dp_mfn & 0x07FFFFFF;
494
495     sign = (mfn < 0x4000000) ? 0: 1;
496     mfn = (mfn <= 0x4000000) ? mfn: (0x8000000 - mfn);
497
498     dbl = ((dp_ctrl >> 12) & 0x1) + 1;
499
500     dbl = dbl * 2;
501     if (sign == 0) {
502         pll_out = (dbl * ref_clk * mfi + ((dbl * ref_clk * mfn) / (mfd + 1))) /
503                   (pdf + 1);
504     } else {
505         pll_out = (dbl * ref_clk * mfi - ((dbl * ref_clk * mfn) / (mfd + 1))) /
506                   (pdf + 1);
507     }
508
509     return (u32)pll_out;
510 }
511
512 /*!
513  * This function returns the emi_core_clk_root clock.
514  */
515 u32 get_emi_core_clk(void)
516 {
517     u32 cbcdr = readl(CCM_BASE_ADDR + CLKCTL_CBCDR);
518     u32 clk_sel = 0, max_pdf = 0, peri_clk = 0, ahb_clk = 0;
519     u32 ret_val = 0;
520
521     max_pdf = (cbcdr >> 10) & 0x7;
522     peri_clk = get_periph_clk();
523     ahb_clk = peri_clk / (max_pdf + 1);
524
525     clk_sel = (cbcdr >> 26) & 1;
526     if (clk_sel == 0) {
527         ret_val = peri_clk;
528     } else {
529         ret_val = ahb_clk ;
530     }
531     return ret_val;
532 }
533
534 /*!
535  * This function returns the main clock value in Hz.
536  */
537 u32 get_main_clock(enum main_clocks clk)
538 {
539     u32 pdf, max_pdf, ipg_pdf, nfc_pdf, clk_sel;
540     u32 pll, ret_val = 0;
541     u32 cacrr = readl(CCM_BASE_ADDR + CLKCTL_CACRR);
542     u32 cbcdr = readl(CCM_BASE_ADDR + CLKCTL_CBCDR);
543     u32 cbcmr = readl(CCM_BASE_ADDR + CLKCTL_CBCMR);
544     u32 cscmr1 = readl(CCM_BASE_ADDR + CLKCTL_CSCMR1);
545     u32 cscdr1 = readl(CCM_BASE_ADDR + CLKCTL_CSCDR1);
546
547     switch (clk) {
548     case CPU_CLK:
549         pdf = cacrr & 0x7;
550         pll = pll_clock(PLL1);
551         ret_val = pll / (pdf + 1);
552         break;
553     case AHB_CLK:
554         max_pdf = (cbcdr >> 10) & 0x7;
555         pll = get_periph_clk();
556         ret_val = pll / (max_pdf + 1);
557         break;
558     case IPG_CLK:
559         max_pdf = (cbcdr >> 10) & 0x7;
560         ipg_pdf = (cbcdr >> 8) & 0x3;
561         pll = get_periph_clk();
562         ret_val = pll / ((max_pdf + 1) * (ipg_pdf + 1));
563         break;
564     case IPG_PER_CLK:
565        clk_sel = cbcmr & 1;
566        if (clk_sel == 0) {
567            clk_sel = (cbcmr >> 1) & 1;
568            pdf = (((cbcdr >> 6) & 3) + 1) * (((cbcdr >> 3) & 7) + 1) * ((cbcdr & 7) + 1);
569            if (clk_sel == 0) {
570                ret_val = get_periph_clk() / pdf;
571            } else {
572                ret_val = get_lp_apm();
573            }
574        } else {
575            /* Same as IPG_CLK */
576            max_pdf = (cbcdr >> 10) & 0x7;
577            ipg_pdf = (cbcdr >> 8) & 0x3;
578            pll = get_periph_clk();
579            ret_val = pll / ((max_pdf + 1) * (ipg_pdf + 1));
580        }
581        break;
582     case DDR_CLK:
583         if (((cbcdr >> 30) & 0x1) == 0x1) {
584             pll = pll_clock(PLL1);
585             pdf = (cbcdr >> 27) & 0x7;
586         } else {
587             clk_sel = (cbcmr >> 10) & 3;
588             pll = get_periph_clk();
589             if (clk_sel == 0) {
590                 /* AXI A */
591                 pdf = (cbcdr >> 16) & 0x7;
592             } else if (clk_sel == 1) {
593                 /* AXI B */
594                 pdf = (cbcdr >> 19) & 0x7;
595             } else if (clk_sel == 2) {
596                 /* EMI SLOW CLOCK ROOT */
597                 pll = get_emi_core_clk();
598                 pdf = (cbcdr >> 22) & 0x7;
599             } else if (clk_sel == 3) {
600                 /* AHB CLOCK */
601                 pdf = (cbcdr >> 10) & 0x7;
602             }
603         }
604
605         ret_val = pll / (pdf + 1);
606         break;
607     case NFC_CLK:
608         pdf = (cbcdr >> 22) & 0x7;
609         nfc_pdf = (cbcdr >> 13) & 0x7;
610         pll = get_emi_core_clk();
611         ret_val = pll / ((pdf + 1) * (nfc_pdf + 1));
612         break;
613     case USB_CLK:
614         clk_sel = (cscmr1 >> 22) & 3;
615         if (clk_sel == 0) {
616             pll = pll_clock(PLL1);
617         } else if (clk_sel == 1) {
618             pll = pll_clock(PLL2);
619         } else if (clk_sel == 2) {
620             pll = pll_clock(PLL3);
621         } else if (clk_sel == 3) {
622             pll = get_lp_apm();
623         }
624         pdf = (cscdr1 >> 8) & 0x7;
625         max_pdf = (cscdr1 >> 6) & 0x3;
626         ret_val = pll / ((pdf + 1) * (max_pdf + 1));
627         break;
628     default:
629         diag_printf("Unknown clock: %d\n", clk);
630         break;
631     }
632
633     return ret_val;
634 }
635
636 /*!
637  * This function returns the peripheral clock value in Hz.
638  */
639 u32 get_peri_clock(enum peri_clocks clk)
640 {
641     u32 ret_val = 0, pdf, pre_pdf, clk_sel;
642     u32 cscmr1 = readl(CCM_BASE_ADDR + CLKCTL_CSCMR1);
643     u32 cscdr1 = readl(CCM_BASE_ADDR + CLKCTL_CSCDR1);
644     u32 cscdr2 = readl(CCM_BASE_ADDR + CLKCTL_CSCDR2);
645     u32 cs1cdr = readl(CCM_BASE_ADDR + CLKCTL_CS1CDR);
646     u32 cs2cdr = readl(CCM_BASE_ADDR + CLKCTL_CS2CDR);
647
648     switch (clk) {
649     case UART1_BAUD:
650     case UART2_BAUD:
651     case UART3_BAUD:
652         pre_pdf = (cscdr1 >> 3) & 0x7;
653         pdf = cscdr1 & 0x7;
654         clk_sel = (cscmr1 >> 24) & 3;
655         if (clk_sel == 0) {
656             ret_val = pll_clock(PLL1) / ((pre_pdf + 1) * (pdf + 1));
657         } else if (clk_sel == 1) {
658             ret_val = pll_clock(PLL2) / ((pre_pdf + 1) * (pdf + 1));
659         } else if (clk_sel == 2) {
660             ret_val = pll_clock(PLL3) / ((pre_pdf + 1) * (pdf + 1));
661         } else {
662             ret_val = get_lp_apm() / ((pre_pdf + 1) * (pdf + 1));
663         }
664         break;
665     case SSI1_BAUD:
666         pre_pdf = (cs1cdr >> 6) & 0x7;
667         pdf = cs1cdr & 0x3F;
668         clk_sel = (cscmr1 >> 14) & 3;
669         if (clk_sel == 0) {
670             ret_val = pll_clock(PLL1) / ((pre_pdf + 1) * (pdf + 1));
671         } else if (clk_sel == 0x1) {
672             ret_val = pll_clock(PLL2) / ((pre_pdf + 1) * (pdf + 1));
673         } else if (clk_sel == 0x2) {
674             ret_val = pll_clock(PLL3) / ((pre_pdf + 1) * (pdf + 1));
675         } else {
676             ret_val = CKIH /((pre_pdf + 1) * (pdf + 1));
677         }
678         break;
679     case SSI2_BAUD:
680         pre_pdf = (cs2cdr >> 6) & 0x7;
681         pdf = cs2cdr & 0x3F;
682         clk_sel = (cscmr1 >> 12) & 3;
683         if (clk_sel == 0) {
684             ret_val = pll_clock(PLL1) / ((pre_pdf + 1) * (pdf + 1));
685         } else if (clk_sel == 0x1) {
686             ret_val = pll_clock(PLL2) / ((pre_pdf + 1) * (pdf + 1));
687         } else if (clk_sel == 0x2) {
688             ret_val = pll_clock(PLL3) / ((pre_pdf + 1) * (pdf + 1));
689         } else {
690             ret_val = CKIH /((pre_pdf + 1) * (pdf + 1));
691         }
692         break;
693     case SPI1_CLK:
694     case SPI2_CLK:
695         pre_pdf = (cscdr2 >> 25) & 0x7;
696         pdf = (cscdr2 >> 19) & 0x3F;
697         clk_sel = (cscmr1 >> 4) & 3;
698         if (clk_sel == 0) {
699             ret_val = pll_clock(PLL1) / ((pre_pdf + 1) * (pdf + 1));
700         } else if (clk_sel == 1) {
701             ret_val = pll_clock(PLL2) / ((pre_pdf + 1) * (pdf + 1));
702         } else if (clk_sel == 2) {
703             ret_val = pll_clock(PLL3) / ((pre_pdf + 1) * (pdf + 1));
704         } else {
705             ret_val = get_lp_apm() / ((pre_pdf + 1) * (pdf + 1));
706         }
707         break;
708     default:
709         diag_printf("%s(): This clock: %d not supported yet \n",
710                     __FUNCTION__, clk);
711         break;
712     }
713
714     return ret_val;
715 }
716
717 #ifdef L2CC_ENABLED
718 /*
719  * This command is added for some simple testing only. It turns on/off
720  * L2 cache regardless of L1 cache state. The side effect of this is
721  * when doing any flash operations such as "fis init", the L2
722  * will be turned back on along with L1 caches even though it is off
723  * by using this command.
724  */
725 RedBoot_cmd("L2",
726             "L2 cache",
727             "[ON | OFF]",
728             do_L2_caches
729            );
730
731 void do_L2_caches(int argc, char *argv[])
732 {
733     u32 oldints;
734     int L2cache_on=0;
735
736     if (argc == 2) {
737         if (strcasecmp(argv[1], "on") == 0) {
738             HAL_DISABLE_INTERRUPTS(oldints);
739             HAL_ENABLE_L2();
740             HAL_RESTORE_INTERRUPTS(oldints);
741         } else if (strcasecmp(argv[1], "off") == 0) {
742             HAL_DISABLE_INTERRUPTS(oldints);
743             HAL_DCACHE_DISABLE_C1();
744             HAL_CACHE_FLUSH_ALL();
745             HAL_DISABLE_L2();
746             HAL_DCACHE_ENABLE_L1();
747             HAL_RESTORE_INTERRUPTS(oldints);
748         } else {
749             diag_printf("Invalid L2 cache mode: %s\n", argv[1]);
750         }
751     } else {
752         HAL_L2CACHE_IS_ENABLED(L2cache_on);
753         diag_printf("L2 cache: %s\n", L2cache_on?"On":"Off");
754     }
755 }
756 #endif //L2CC_ENABLED
757
758 #define IIM_ERR_SHIFT       8
759 #define POLL_FUSE_PRGD      (IIM_STAT_PRGD | (IIM_ERR_PRGE << IIM_ERR_SHIFT))
760 #define POLL_FUSE_SNSD      (IIM_STAT_SNSD | (IIM_ERR_SNSE << IIM_ERR_SHIFT))
761
762 static void fuse_op_start(void)
763 {
764     /* Do not generate interrupt */
765     writel(0, IIM_BASE_ADDR + IIM_STATM_OFF);
766     // clear the status bits and error bits
767     writel(0x3, IIM_BASE_ADDR + IIM_STAT_OFF);
768     writel(0xFE, IIM_BASE_ADDR + IIM_ERR_OFF);
769 }
770
771 /*
772  * The action should be either:
773  *          POLL_FUSE_PRGD
774  * or:
775  *          POLL_FUSE_SNSD
776  */
777 static int poll_fuse_op_done(int action)
778 {
779
780     u32 status, error;
781
782     if (action != POLL_FUSE_PRGD && action != POLL_FUSE_SNSD) {
783         diag_printf("%s(%d) invalid operation\n", __FUNCTION__, action);
784         return -1;
785     }
786
787     /* Poll busy bit till it is NOT set */
788     while ((readl(IIM_BASE_ADDR + IIM_STAT_OFF) & IIM_STAT_BUSY) != 0 ) {
789     }
790
791     /* Test for successful write */
792     status = readl(IIM_BASE_ADDR + IIM_STAT_OFF);
793     error = readl(IIM_BASE_ADDR + IIM_ERR_OFF);
794
795     if ((status & action) != 0 && (error & (action >> IIM_ERR_SHIFT)) == 0) {
796         if (error) {
797             diag_printf("Even though the operation seems successful...\n");
798             diag_printf("There are some error(s) at addr=0x%x: 0x%x\n",
799                         (IIM_BASE_ADDR + IIM_ERR_OFF), error);
800         }
801         return 0;
802     }
803     diag_printf("%s(%d) failed\n", __FUNCTION__, action);
804     diag_printf("status address=0x%x, value=0x%x\n",
805                 (IIM_BASE_ADDR + IIM_STAT_OFF), status);
806     diag_printf("There are some error(s) at addr=0x%x: 0x%x\n",
807                 (IIM_BASE_ADDR + IIM_ERR_OFF), error);
808     return -1;
809 }
810
811 static void sense_fuse(int bank, int row, int bit)
812 {
813     int addr, addr_l, addr_h, reg_addr;
814
815     fuse_op_start();
816
817     addr = ((bank << 11) | (row << 3) | (bit & 0x7));
818     /* Set IIM Program Upper Address */
819     addr_h = (addr >> 8) & 0x000000FF;
820     /* Set IIM Program Lower Address */
821     addr_l = (addr & 0x000000FF);
822
823 #ifdef IIM_FUSE_DEBUG
824     diag_printf("%s: addr_h=0x%x, addr_l=0x%x\n",
825                 __FUNCTION__, addr_h, addr_l);
826 #endif
827     writel(addr_h, IIM_BASE_ADDR + IIM_UA_OFF);
828     writel(addr_l, IIM_BASE_ADDR + IIM_LA_OFF);
829     /* Start sensing */
830     writel(0x8, IIM_BASE_ADDR + IIM_FCTL_OFF);
831     if (poll_fuse_op_done(POLL_FUSE_SNSD) != 0) {
832         diag_printf("%s(bank: %d, row: %d, bit: %d failed\n",
833                     __FUNCTION__, bank, row, bit);
834     }
835     reg_addr = IIM_BASE_ADDR + IIM_SDAT_OFF;
836     diag_printf("fuses at (bank:%d, row:%d) = 0x%x\n", bank, row, readl(reg_addr));
837 }
838
839 void do_fuse_read(int argc, char *argv[])
840 {
841     unsigned long bank, row;
842
843     if (argc == 1) {
844         diag_printf("Useage: fuse_read <bank> <row>\n");
845         return;
846     } else if (argc == 3) {
847         if (!parse_num(*(&argv[1]), &bank, &argv[1], " ")) {
848                 diag_printf("Error: Invalid parameter\n");
849             return;
850         }
851         if (!parse_num(*(&argv[2]), &row, &argv[2], " ")) {
852                 diag_printf("Error: Invalid parameter\n");
853                 return;
854             }
855
856         diag_printf("Read fuse at bank:%ld row:%ld\n", bank, row);
857         sense_fuse(bank, row, 0);
858
859     } else {
860         diag_printf("Passing in wrong arguments: %d\n", argc);
861         diag_printf("Useage: fuse_read <bank> <row>\n");
862     }
863 }
864
865 /* Blow fuses based on the bank, row and bit positions (all 0-based)
866 */
867 static int fuse_blow(int bank,int row,int bit)
868 {
869     int addr, addr_l, addr_h, ret = -1;
870
871     fuse_op_start();
872
873     /* Disable IIM Program Protect */
874     writel(0xAA, IIM_BASE_ADDR + IIM_PREG_P_OFF);
875
876     addr = ((bank << 11) | (row << 3) | (bit & 0x7));
877     /* Set IIM Program Upper Address */
878     addr_h = (addr >> 8) & 0x000000FF;
879     /* Set IIM Program Lower Address */
880     addr_l = (addr & 0x000000FF);
881
882 #ifdef IIM_FUSE_DEBUG
883     diag_printf("blowing addr_h=0x%x, addr_l=0x%x\n", addr_h, addr_l);
884 #endif
885
886     writel(addr_h, IIM_BASE_ADDR + IIM_UA_OFF);
887     writel(addr_l, IIM_BASE_ADDR + IIM_LA_OFF);
888     /* Start Programming */
889     writel(0x31, IIM_BASE_ADDR + IIM_FCTL_OFF);
890     if (poll_fuse_op_done(POLL_FUSE_PRGD) == 0) {
891         ret = 0;
892     }
893
894     /* Enable IIM Program Protect */
895     writel(0x0, IIM_BASE_ADDR + IIM_PREG_P_OFF);
896     return ret;
897 }
898
899 /*
900  * This command is added for burning IIM fuses
901  */
902 RedBoot_cmd("fuse_read",
903             "read some fuses",
904             "<bank> <row>",
905             do_fuse_read
906            );
907
908 RedBoot_cmd("fuse_blow",
909             "blow some fuses",
910             "<bank> <row> <value>",
911             do_fuse_blow
912            );
913
914 #define         INIT_STRING              "12345678"
915
916 void quick_itoa(u32 num, char *a)
917 {
918     int i, j, k;
919     for (i = 0; i <= 7; i++) {
920         j = (num >> (4 * i)) & 0xF;
921         k = (j < 10) ? '0' : ('a' - 0xa);
922         a[i] = j + k;
923     }
924 }
925
926 void do_fuse_blow(int argc, char *argv[])
927 {
928     unsigned long bank, row, value;
929     unsigned int reg, i;
930
931     if (argc != 4) {
932         diag_printf("It is too dangeous for you to use this command.\n");
933         return;
934         }
935         if (!parse_num(*(&argv[1]), &bank, &argv[1], " ")) {
936                 diag_printf("Error: Invalid parameter\n");
937                 return;
938         }
939         if (!parse_num(*(&argv[2]), &row, &argv[2], " ")) {
940                 diag_printf("Error: Invalid parameter\n");
941                 return;
942         }
943         if (!parse_num(*(&argv[3]), &value, &argv[3], " ")) {
944                 diag_printf("Error: Invalid parameter\n");
945                 return;
946         }
947
948     reg = readl(CCM_BASE_ADDR + 0x64);
949     reg |= 0x10;
950     writel(reg, CCM_BASE_ADDR + 0x64);
951
952         diag_printf("Blowing fuse at bank:%ld row:%ld value:%ld\n",
953                     bank, row, value);
954         for (i = 0; i < 8; i++) {
955             if (((value >> i) & 0x1) == 0) {
956                 continue;
957             }
958             if (fuse_blow(bank, row, i) != 0) {
959                 diag_printf("fuse_blow(bank: %ld, row: %ld, bit: %d failed\n",
960                             bank, row, i);
961             } else {
962                 diag_printf("fuse_blow(bank: %ld, row: %ld, bit: %d successful\n",
963                             bank, row, i);
964             }
965         }
966         sense_fuse(bank, row, 0);
967     reg &= ~0x10;
968     writel(reg, CCM_BASE_ADDR + 0x64);
969 }
970
971 /* precondition: m>0 and n>0.  Let g=gcd(m,n). */
972 int gcd(int m, int n)
973 {
974     int t;
975     while(m > 0) {
976         if(n > m) {t = m; m = n; n = t;} /* swap */
977         m -= n;
978     }
979     return n;
980 }
981
982 #define CLOCK_SRC_DETECT_MS         100
983 #define CLOCK_IPG_DEFAULT           66500000
984 #define CLOCK_SRC_DETECT_MARGIN     500000
985 void mxc_show_clk_input(void)
986 {
987 //    u32 c1, c2, diff, ipg_real, num = 0;
988
989     return;  // FIXME
990 #if 0
991     switch (prcs) {
992     case 0x01:
993         diag_printf("FPM enabled --> 32KHz input source\n");
994         return;
995     case 0x02:
996         break;
997     default:
998         diag_printf("Error %d: unknown clock source %d\n", __LINE__, prcs);
999         return;
1000     }
1001
1002     // enable GPT with IPG clock input
1003     writel(0x241, GPT_BASE_ADDR + GPTCR);
1004     // prescaler = 1
1005     writel(0, GPT_BASE_ADDR + GPTPR);
1006
1007     c1 = readl(GPT_BASE_ADDR + GPTCNT);
1008     // use 32KHz input clock to get the delay
1009     hal_delay_us(CLOCK_SRC_DETECT_MS * 1000);
1010     c2 = readl(GPT_BASE_ADDR + GPTCNT);
1011     diff = (c2 > c1) ? (c2 - c1) : (0xFFFFFFFF - c1 + c2);
1012
1013     ipg_real = diff * (1000 / CLOCK_SRC_DETECT_MS);
1014
1015     if (num != 0) {
1016         diag_printf("Error: Actural clock input is %d MHz\n", num);
1017         diag_printf("       ipg_real=%d CLOCK_IPG_DEFAULT - CLOCK_SRC_DETECT_MARGIN=%d\n\n",
1018                     ipg_real, CLOCK_IPG_DEFAULT - CLOCK_SRC_DETECT_MARGIN);
1019         hal_delay_us(2000000);
1020     } else {
1021         diag_printf("ipg_real=%d CLOCK_IPG_DEFAULT - CLOCK_SRC_DETECT_MARGIN=%d\n\n",
1022                     ipg_real, CLOCK_IPG_DEFAULT - CLOCK_SRC_DETECT_MARGIN);
1023     }
1024 #endif
1025 }
1026
1027 RedBoot_init(mxc_show_clk_input, RedBoot_INIT_LAST);
1028 #if 0
1029 void imx_power_mode(int mode)
1030 {
1031     volatile unsigned int val;
1032     switch (mode) {
1033     case 2:
1034         writel(0x0000030f, GPC_PGR);
1035         writel(0x1, SRPGCR_EMI);
1036         writel(0x1, SRPGCR_ARM);
1037         writel(0x1, PGC_PGCR_VPU);
1038         writel(0x1, PGC_PGCR_IPU);
1039
1040
1041     case 1:
1042         // stop mode - from validation code
1043         // Set DSM_INT_HOLDOFF bit in TZIC
1044         // If the TZIC didn't write the bit then there was interrupt pending
1045         // It will be serviced while we're in the loop
1046         // So we write to this bit again
1047         while (readl(INTC_BASE_ADDR + 0x14) == 0) {
1048             writel(1, INTC_BASE_ADDR + 0x14);
1049             // Wait few cycles
1050             __asm("nop");
1051             __asm("nop");
1052             __asm("nop");
1053             __asm("nop");
1054             __asm("nop");
1055             __asm("nop");
1056             __asm("nop");
1057         }
1058         diag_printf("Entering stop mode\n");
1059         val = readl(CCM_BASE_ADDR + 0x74);
1060         val = (val & 0xfffffffc) | 0x2; // set STOP mode
1061         writel(val, CCM_BASE_ADDR + 0x74);
1062         val = readl(PLATFORM_LPC_REG);
1063         writel(val | (1 << 16), PLATFORM_LPC_REG);// ENABLE DSM in ELBOW submodule of ARM platform
1064         writel(val | (1 << 17), PLATFORM_LPC_REG);// ENABLE DSM in ELBOW submodule of ARM platform
1065         break;
1066     default:
1067         break;
1068     }
1069
1070     hal_delay_us(50);
1071
1072     asm("mov r1, #0");
1073     asm("mcr p15, 0, r1, c7, c0, 4");
1074 }
1075
1076 void do_power_mode(int argc, char *argv[])
1077 {
1078     int mode;
1079
1080     if (argc == 1) {
1081         diag_printf("Useage: power_mode <mode>\n");
1082         return;
1083     } else if (argc == 2) {
1084         if (!parse_num(*(&argv[1]), (unsigned long *)&mode, &argv[1], " ")) {
1085                 diag_printf("Error: Invalid parameter\n");
1086             return;
1087         }
1088         diag_printf("Entering power mode: %d\n", mode);
1089         imx_power_mode(mode);
1090
1091     } else {
1092         diag_printf("Passing in wrong arguments: %d\n", argc);
1093         diag_printf("Useage: power_mode <mode>\n");
1094     }
1095 }
1096
1097 /*
1098  * This command is added for burning IIM fuses
1099  */
1100 RedBoot_cmd("power_mode",
1101             "Enter various power modes:",
1102             "\n\
1103             <0> - WAIT\n\
1104             <1> - SRPG\n\
1105             <2> - STOP\n\
1106             <3> - STOP with Power-Gating\n\
1107             -- need reset after issuing the command",
1108             do_power_mode
1109            );
1110 #endif