]> git.karo-electronics.de Git - karo-tx-redboot.git/blob - packages/hal/arm/mxc91221/var/v2_0/src/cmds.c
Initial revision
[karo-tx-redboot.git] / packages / hal / arm / mxc91221 / 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 ARM_DIV_MAX     4       //should be enough even though max is 12
57 #define IPG_DIV_MAX     4
58 #define AHB_DIV_MAX     8
59 #define NFC_DIV_MAX     16
60
61 #define REF_IN_CLK_NUM  4
62 struct fixed_pll_mfd {
63     u32 ref_clk_hz;
64     u32 mfd;
65 };
66 const struct fixed_pll_mfd fixed_mfd[REF_IN_CLK_NUM] = {
67     {FREQ_CKIH_26M,       26 * 16},    // 416
68     {0,                   0},      // reserved
69     {2 * FREQ_CKIH_26M,   26 * 16},    // 416
70     {0,                   0},      // reserved
71 };
72
73 struct pll_param {
74     u32 pd;
75     u32 mfi;
76     u32 mfn;
77     u32 mfd;
78 };
79
80 #define PLL_FREQ_MAX(_ref_clk_)    (2 * _ref_clk_ * PLL_MFI_MAX)
81 #define PLL_FREQ_MIN(_ref_clk_)    ((2 * _ref_clk_ * (PLL_MFI_MIN - 1)) / PLL_PD_MAX)
82 #define AHB_CLK_MAX     133333333
83 #define IPG_CLK_MAX     (AHB_CLK_MAX / 2)
84 #define NFC_CLK_MAX     25000000
85
86 #define ERR_WRONG_CLK   -1
87 #define ERR_NO_MFI      -2
88 #define ERR_NO_MFN      -3
89 #define ERR_NO_PD       -4
90 #define ERR_NO_ARM_DIV  -5
91 #define ERR_NO_AHB_DIV  -6
92
93 int gcd(int m, int n);
94
95 static void clock_setup(int argc, char *argv[]);
96 static void ckol(int argc, char *argv[]);
97 static void ckoh(int argc, char *argv[]);
98
99 static volatile u32 *crm_ap_base = REG32_PTR(CRM_AP_BASE_ADDR);
100
101 static volatile u32 *pll_base[] =
102 {
103     REG32_PTR(PLL0_BASE_ADDR),     // MCU PLL
104     REG32_PTR(PLL1_BASE_ADDR),     // DSP PLL
105     REG32_PTR(PLL2_BASE_ADDR),     // USB PLL
106 };
107
108 #define NOT_ON_VAL  0xDEADBEEF
109
110 RedBoot_cmd("clock",
111             "Setup/Display clock (max AHB=133MHz, max IPG=66.5MHz)\nSyntax:",
112             "[<core clock in MHz> [:<AHB-to-core divider>[:<IPG-to-AHB divider>]]] \n\n\
113 If a divider is zero or no divider is specified, the optimal divider values \n\
114 will be chosen. Examples:\n\
115    [clock]         -> Show various clocks\n\
116    [clock 399]     -> Core=399  AHB=133           IPG=66.5\n\
117    [clock 399:6]   -> Core=399  AHB=66.5(Core/8)  IPG=66.5\n\
118    [clock 399:6:2] -> Core=532  AHB=66.5(Core/8)  IPG=33.25(AHB/2)\n",
119             clock_setup
120            );
121
122 /*!
123  * This is to calculate various parameters based on reference clock and
124  * targeted clock based on the equation:
125  *      t_clk = 2*ref_freq*(mfi + mfn/(mfd+1))/(pd+1)
126  * This calculation is based on a fixed MFD value for simplicity.
127  *
128  * @param ref       reference clock freq in Hz
129  * @param target    targeted clock in Hz
130  * @param p_pd      calculated pd value (pd value from register + 1) upon return
131  * @param p_mfi     calculated actual mfi value upon return
132  * @param p_mfn     calculated actual mfn value upon return
133  * @param p_mfd     fixed mfd value (mfd value from register + 1) upon return
134  *
135  * @return          0 if successful; non-zero otherwise.
136  */
137 int calc_pll_params(u32 ref, u32 target, struct pll_param *pll)
138 {
139     u64 pd, mfi = 1, mfn, mfd, n_target = target, n_ref = ref, i;
140
141     // make sure targeted freq is in the valid range. Otherwise the
142     // following calculation might be wrong!!!
143     if (n_target < PLL_FREQ_MIN(ref) || n_target > PLL_FREQ_MAX(ref))
144         return ERR_WRONG_CLK;
145     for (i = 0; ; i++) {
146         if (i == REF_IN_CLK_NUM)
147             return ERR_WRONG_CLK;
148         if (fixed_mfd[i].ref_clk_hz == ref) {
149             mfd = fixed_mfd[i].mfd;
150             break;
151         }
152     }
153     // use n_target and n_ref to avoid overflow
154     for (pd = 1; pd <= PLL_PD_MAX; pd++) {
155         mfi = (n_target * pd) / (2 * n_ref);
156         if (mfi > PLL_MFI_MAX)
157             return ERR_NO_MFI;
158         else if (mfi < 5)
159             continue;
160         break;
161     }
162     // Now got pd and mfi already
163     mfn = (((n_target * pd) / 2 - n_ref * mfi) * mfd) / n_ref;
164 #ifdef CMD_CLOCK_DEBUG
165     diag_printf("%d: ref=%d, target=%d, pd=%d, mfi=%d,mfn=%d, mfd=%d\n",
166                 __LINE__, ref, (u32)n_target, (u32)pd, (u32)mfi, (u32)mfn, (u32)mfd);
167 #endif
168     i = 1;
169     if (mfn != 0)
170         i = gcd(mfd, mfn);
171     pll->pd = (u32)pd;
172     pll->mfi = (u32)mfi;
173     pll->mfn = (u32)(mfn / i);
174     pll->mfd = (u32)(mfd / i);
175     return 0;
176 }
177
178 /*!
179  * This function assumes the expected core clock has to be changed by
180  * modifying the PLL. This is NOT true always but for most of the times,
181  * it is. So it assumes the PLL output freq is the same as the expected
182  * core clock (arm_div=1) unless the core clock is less than PLL_FREQ_MIN.
183  * In the latter case, it will try to increase the arm_div value until
184  * (arm_div*core_clk) is greater than PLL_FREQ_MIN. It then makes call to
185  * calc_pll_params() and obtains the values of PD, MFI,MFN, MFD based
186  * on the targeted PLL and reference input clock to the PLL. Lastly,
187  * it sets the register based on these values along with the dividers.
188  * Note 1) There is no value checking for the passed-in divider values
189  *         so the caller has to make sure those values are sensible.
190  *      2) Also adjust the NFC divider such that the NFC clock doesn't
191  *         exceed NFC_CLK_MAX.
192  *      3) This function should not have allowed diag_printf() calls since
193  *         the serial driver has been stoped. But leave then here to allow
194  *         easy debugging by NOT calling the cyg_hal_plf_serial_stop().
195  *      4) The IPG divider doesn't go through AHB divider
196  *
197  * @param ref       pll input reference clock (32KHz or 26MHz)
198  * @param core_clk  core clock in Hz
199  * @param ahb_div   ahb divider to divide the core clock to get ahb clock
200  *                  (ahb_div - 1) needs to be set in the register
201  * @param ipg_div   ipg divider to divide the core clock to get ipg clock
202  *                  (ipg_div - 1) needs to be set in the register
203  # @return          0 if successful; non-zero otherwise
204  */
205 int configure_clock(u32 ref, u32 core_clk, u32 ahb_div, u32 ipg_div)
206 {
207     u32 pll, arm_div = 1, nfc_div, acdr, acder2;
208     struct pll_param pll_param;
209     int ret;
210
211     // assume pll default to core clock first
212     pll = core_clk;
213     // when core_clk >= PLL_FREQ_MIN, the arm_div can be 1.
214     // Otherwise, need to calculate arm_div value below and adjust the targeted pll
215     if (core_clk < PLL_FREQ_MIN(ref)) {
216         for (arm_div = 1; arm_div <= ARM_DIV_MAX; arm_div++) {
217             if ((core_clk * arm_div) > PLL_FREQ_MIN(ref)) {
218                 break;
219             }
220         }
221         if (arm_div == (ARM_DIV_MAX + 1)) {
222             diag_printf("can't make arm_div=%d\n", arm_div);
223             return ERR_NO_ARM_DIV;
224         }
225         pll = core_clk * arm_div;
226     }
227
228     // get nfc_div - make sure optimal NFC clock but less than NFC_CLK_MAX
229     for (nfc_div = 1; nfc_div <= NFC_DIV_MAX; nfc_div++) {
230         if ((pll / (ahb_div * nfc_div)) <= NFC_CLK_MAX) {
231             break;
232         }
233     }
234
235     // pll is now the targeted pll output. Use it along with ref input clock
236     // to get pd, mfi, mfn, mfd
237     if ((ret = calc_pll_params(ref, pll, &pll_param)) != 0) {
238         diag_printf("can't find pll parameters: %d\n", ret);
239         return ret;
240     }
241 #ifdef CMD_CLOCK_DEBUG
242     diag_printf("ref=%d, pll=%d, pd=%d, mfi=%d,mfn=%d, mfd=%d\n",
243                 ref, pll, pll_param.pd, pll_param.mfi, pll_param.mfn, pll_param.mfd);
244 #endif
245     acdr = ((arm_div - 1) << 8) |
246            ((ahb_div - 1) << 4) |
247            (ipg_div - 1);
248
249     acder2 = (readl(CRM_AP_BASE_ADDR + CRM_AP_ACDER) & 0xFFF0FFFF) |
250              ((nfc_div - 1) << 16);
251
252     // switch to ap_ref_clk
253     writel(readl(CRM_AP_BASE_ADDR + CRM_AP_ACSR) & (~0x1),
254            CRM_AP_BASE_ADDR + CRM_AP_ACSR);
255
256     // change the dividers
257     writel(acdr, CRM_AP_BASE_ADDR + CRM_AP_ACDR);
258     writel(acder2, CRM_AP_BASE_ADDR + CRM_AP_ACDER);
259
260     // adjust pll settings
261     writel(((pll_param.pd - 1) << 0) | (pll_param.mfi << 4),
262            PLL0_BASE_ADDR + PLL_DP_OP);
263     writel(pll_param.mfn, PLL0_BASE_ADDR + PLL_DP_MFN);
264     writel(pll_param.mfd - 1, PLL0_BASE_ADDR + PLL_DP_MFD);
265     writel(((pll_param.pd - 1) << 0) | (pll_param.mfi << 4),
266            PLL0_BASE_ADDR + PLL_DP_HFS_OP);
267     writel(pll_param.mfn, PLL0_BASE_ADDR + PLL_DP_HFS_MFN);
268     writel(pll_param.mfd - 1, PLL0_BASE_ADDR + PLL_DP_HFS_MFD);
269
270     // switch back to pll
271     writel(readl(CRM_AP_BASE_ADDR + CRM_AP_ACSR) | 0x1,
272            CRM_AP_BASE_ADDR + CRM_AP_ACSR);
273
274     return 0;
275 }
276
277 static void clock_setup(int argc,char *argv[])
278 {
279     u32 i, core_clk, ipg_div, data[3], uart1_baud, ssi1_baud;
280     u32 csi_baud, ahb_div, ahb_clk, ipg_clk, clk_sel, ref_clk;
281     int ret;
282
283     if (argc == 1)
284         goto print_clock;
285     for (i = 0;  i < 3;  i++) {
286         unsigned long temp;
287         if (!parse_num(*(&argv[1]), &temp, &argv[1], ":")) {
288             diag_printf("Error: Invalid parameter\n");
289             return;
290         }
291         data[i] = temp;
292     }
293
294     core_clk = data[0] * SZ_DEC_1M;
295     ahb_div = data[1];  // actual register field + 1
296     ipg_div = data[2];  // actual register field + 1
297
298     // since only support set clock for the AP domain, get ref input clock
299     // for the AP domain.
300     clk_sel = MXC_GET_FIELD(readl(PLL0_BASE_ADDR + PLL_DP_CTL), 2, 8);
301     ref_clk = fixed_mfd[clk_sel].ref_clk_hz;
302
303     if (core_clk < (PLL_FREQ_MIN(ref_clk) / ARM_DIV_MAX) ||
304         core_clk > PLL_FREQ_MAX(ref_clk)) {
305         diag_printf("Targeted core clock should be within [%d - %d]\n",
306                     PLL_FREQ_MIN(ref_clk) / ARM_DIV_MAX,
307                     PLL_FREQ_MAX(ref_clk));
308         return;
309     }
310
311     // find the ahb divider
312     if (ahb_div > AHB_DIV_MAX) {
313         diag_printf("Invalid AHB divider: %d. Maximum value is %d\n",
314                     ahb_div, AHB_DIV_MAX);
315         return;
316     }
317     if (ahb_div == 0) {
318         // no HCLK divider specified
319         for (ahb_div = 1; ; ahb_div++) {
320             if ((core_clk / ahb_div) <= AHB_CLK_MAX)
321                 break;
322         }
323     }
324     if (ahb_div > AHB_DIV_MAX || (core_clk / ahb_div) > AHB_CLK_MAX) {
325         diag_printf("Can't make AHB=%d since max=%d\n",
326                     core_clk / ahb_div, AHB_CLK_MAX);
327         return;
328     }
329
330     // find the ipg divider
331     ahb_clk = core_clk / ahb_div;
332     if (ipg_div == 0) {
333         ipg_div++;          // At least =1
334         if (ahb_clk > IPG_CLK_MAX)
335             ipg_div++;      // Make it =2
336     }
337     ipg_clk = ahb_clk / ipg_div;
338     if (ipg_div > IPG_DIV_MAX || ipg_clk > IPG_CLK_MAX) {
339         if (ipg_div > IPG_DIV_MAX)
340             diag_printf("Invalid IPG divider: %d. Max is: %d\n",
341                         ipg_div / ahb_div, IPG_DIV_MAX / ahb_div);
342         else
343             diag_printf("Can't make IPG=%dHz since max=%dHz\n",
344                         ipg_clk, IPG_CLK_MAX);
345         return;
346     }
347
348     diag_printf("Trying to set core=%d ahb=%d ipg=%d...\n",
349                 core_clk, ahb_clk, ipg_clk);
350
351     // stop the serial to be ready to adjust the clock
352     hal_delay_us(100000);
353     cyg_hal_plf_serial_stop();
354     // adjust the clock
355     ret = configure_clock(ref_clk, core_clk, ahb_div, ipg_div);
356     // restart the serial driver
357     cyg_hal_plf_serial_init();
358     hal_delay_us(100000);
359
360     if (ret != 0) {
361         diag_printf("Failed to setup clock: %d\n", ret);
362         return;
363     }
364     diag_printf("\n<<<New clock setting>>>\n");
365
366     // Now printing clocks
367 print_clock:
368     diag_printf("\nMCUPLL\t\tUSBPLL\t\tDSPPLL\n");
369     diag_printf("========================================\n");
370     diag_printf("%-16d%-16d%-16d\n\n", pll_clock(PLL0), pll_clock(PLL2),
371                 pll_clock(PLL1));
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     uart1_baud = get_peri_clock(UART1_BAUD);
383     ssi1_baud = get_peri_clock(SSI1_BAUD);
384     csi_baud = get_peri_clock(CSI_BAUD);
385
386     diag_printf("UART1/2\t\tSSI1\t\tCSI\n");
387     diag_printf("===========================================");
388     diag_printf("=============================\n");
389
390     (uart1_baud != NOT_ON_VAL) ? diag_printf("%-16d", uart1_baud) :
391                                  diag_printf("%-16s", "OFF");
392     (ssi1_baud != NOT_ON_VAL) ? diag_printf("%-16d", ssi1_baud) :
393                                 diag_printf("%-16s", "OFF");
394     (csi_baud != NOT_ON_VAL) ? diag_printf("%-16d", csi_baud ) :
395                                diag_printf("%-16s", "OFF");
396     diag_printf("\n\n");
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 dp_op, dp_mfd, dp_mfn, clk_sel;
406
407     clk_sel = MXC_GET_FIELD(pll_base[pll][PLL_DP_CTL >> 2], 2, 8);
408     ref_clk = fixed_mfd[clk_sel].ref_clk_hz;
409
410     if ((pll_base[pll][PLL_DP_CTL >> 2] & 0x80) == 0) {
411         dp_op = pll_base[pll][PLL_DP_OP >> 2];
412         dp_mfd = pll_base[pll][PLL_DP_MFD >> 2];
413         dp_mfn = pll_base[pll][PLL_DP_MFN >> 2];
414     } else {
415         dp_op = pll_base[pll][PLL_DP_HFS_OP >> 2];
416         dp_mfd = pll_base[pll][PLL_DP_HFS_MFD >> 2];
417         dp_mfn = pll_base[pll][PLL_DP_HFS_MFN >> 2];
418     }
419     pdf = dp_op & 0xF;
420     mfi = (dp_op >> 4) & 0xF;
421     mfi = (mfi <= 5) ? 5: mfi;
422     mfd = dp_mfd & 0x07FFFFFF;
423     mfn = dp_mfn & 0x07FFFFFF;
424
425     sign = (mfn < 0x4000000) ? 0: 1;
426     mfn = (mfn <= 0x4000000) ? mfn: (0x8000000 - mfn);
427
428     if (sign == 0) {
429         pll_out = (2 * ref_clk * mfi + ((2 * ref_clk * mfn) / (mfd + 1))) /
430                   (pdf + 1);
431     } else {
432         pll_out = (2 * ref_clk * mfi - ((2 * ref_clk * mfn) / (mfd + 1))) /
433                   (pdf + 1);
434     }
435
436     return (u32)pll_out;
437 }
438
439 const u32 CRM_SMALL_DIV[] = {2, 3, 4, 5, 6, 8, 10, 12};
440
441 /*!
442  * This function returns the main clock dividers.
443  */
444 u32 clock_divider(enum main_clocks clk)
445 {
446     u32 div = 0;
447     u32 acdr, acder;
448
449     acdr = crm_ap_base[CRM_AP_ACDR >> 2];
450     acder = crm_ap_base[CRM_AP_ACDER >> 2];
451
452     switch (clk) {
453     case CPU_CLK:
454         div = (acdr >> 8) & 0x7;
455         div = (div > 3) ? 1 : (div + 1);
456         break;
457     case AHB_CLK:
458         div = ((acdr >> 4) & 0x7) + 1;
459         break;
460     case IPG_CLK:
461         div = ((acdr >> 0) & 0x3) + 1;
462         break;
463     case NFC_CLK:
464         div = ((acder >> 16) & 0xF) + 1;
465         break;
466     case USB_CLK:
467         div = (acder >> 0) & 0xF;
468         div = (div > 7) ? 1 : (CRM_SMALL_DIV[div]);
469         break;
470     default:
471         diag_printf("Wrong clock: %d\n", clk);
472         break;
473     }
474
475     return div;
476 }
477
478 /*!
479  * This function returns the peripheral clock dividers.
480  */
481 u32 clock_peri_divider(enum peri_clocks clk)
482 {
483     u32 div = 0;
484     u32 acder;
485
486     acder = crm_ap_base[CRM_AP_ACDER >> 2];
487
488     switch (clk) {
489     case SSI1_BAUD:
490         div = (acder >> 8) & 0x3F;
491         //double the divider to avoid FP
492         div = (2 * ((div >> 1) & 0x1F)) + (div & 0x1);
493         div = (div == 0 || div == 1) ? (2 * 62) : div;
494         break;
495     case CSI_BAUD:
496         div = (acder >> 24) & 0x3F;
497         //double the divider to avoid FP
498         div = (2 * ((div >> 1) & 0x1F)) + (div & 0x1);
499         div = (div == 0 || div == 1) ? (2 * 62) : div;
500         break;
501     default:
502         diag_printf("Wrong clock: %d\n", clk);
503         break;
504     }
505
506     return div;
507 }
508
509 void get_ref_clk(u32 *ap_unc_pat_ref, u32 *ap_ref_x2,
510                  u32 *ap_ref)
511 {
512     u32 ap_pat_ref_div_1, ascsr, adcr, clk_sel, ref_clk;
513
514     clk_sel = MXC_GET_FIELD(readl(PLL0_BASE_ADDR + PLL_DP_CTL), 2, 8);
515     ref_clk = fixed_mfd[clk_sel].ref_clk_hz;
516
517     ascsr = crm_ap_base[CRM_AP_ASCSR >> 2];
518
519     ap_pat_ref_div_1 = ((ascsr >> 3) & 0x1) + 1;
520
521     *ap_ref_x2 =  ref_clk;
522     *ap_ref = (*ap_ref_x2) / ap_pat_ref_div_1;
523 }
524
525 /*!
526  * This function returns the main clock value in Hz.
527  */
528 u32 get_main_clock(enum main_clocks clk)
529 {
530     u32 ret_val = 0, apsel, ap_clk_pre_dfs, acsr, acder;
531     u32 ap_ref_x2_clk, ap_ref_clk, usbsel, ap_unc_pat_ref;
532
533     acsr = crm_ap_base[CRM_AP_ACSR >> 2];
534     acder = crm_ap_base[CRM_AP_ACDER >> 2];
535
536     get_ref_clk(&ap_unc_pat_ref, &ap_ref_x2_clk, &ap_ref_clk);
537
538     if ((acsr & 0x1) == 0) {
539         // inverted pat_ref is selected
540         ap_clk_pre_dfs = ap_ref_clk;
541     } else {
542         apsel = 0;
543         ap_clk_pre_dfs = pll_clock(apsel);
544     }
545
546     switch (clk) {
547     case CPU_CLK:
548         ret_val = ap_clk_pre_dfs / clock_divider(CPU_CLK);
549         break;
550     case AHB_CLK:
551         ret_val = ap_clk_pre_dfs / clock_divider(AHB_CLK);
552         break;
553     case IPG_CLK:
554
555         ret_val = ap_clk_pre_dfs / (clock_divider(AHB_CLK) *
556                                     clock_divider(IPG_CLK));
557         break;
558     case NFC_CLK:
559         if ((acder & (1 << 20)) == 0) {
560             diag_printf("Warning: NFC clock is not enabled !!!\n");
561         } else {
562             ret_val = ap_clk_pre_dfs / (clock_divider(AHB_CLK) *
563                                         clock_divider(NFC_CLK));
564         }
565         break;
566     case USB_CLK:
567         if ((acder & (1 << 4)) == 0) {
568             diag_printf("Warning: USB clock is not enabled !!!\n");
569         } else {
570             if ((acsr & 0x1) == 0) {
571                 // inverted pat_ref is selected
572                 ret_val = ap_ref_clk / clock_divider(USB_CLK);
573             } else {
574                 usbsel = 2;
575                 ret_val = pll_clock(usbsel) / clock_divider(USB_CLK);
576             }
577         }
578         break;
579     default:
580         break;
581     }
582
583     return ret_val;
584 }
585
586 /*!
587  * This function returns the peripheral clock value in Hz.
588  */
589 u32 get_peri_clock(enum peri_clocks clk)
590 {
591     u32 ascsr, acder, ret_val = 0, sel;
592
593     acder = crm_ap_base[CRM_AP_ACDER >> 2];
594     ascsr = crm_ap_base[CRM_AP_ASCSR >> 2];
595
596     switch (clk) {
597     case UART1_BAUD:
598     case UART2_BAUD:
599         ret_val = get_main_clock(IPG_CLK);
600         break;
601     case SSI1_BAUD:
602         if ((acder & (1 << 14)) == 0) {
603             return NOT_ON_VAL;
604         }
605
606         sel = ascsr & 0x1;
607         if (sel == 0) {
608             // Don't forget to double the divider
609             ret_val = (2 * pll_clock(sel)) / (clock_peri_divider(SSI1_BAUD));
610         } else if (sel == 1) {
611             sel++;
612             ret_val = (2 * pll_clock(sel)) / (clock_peri_divider(SSI1_BAUD));;
613         }
614         break;
615     case CSI_BAUD:
616         if ((acder & (1 << 30)) == 0) {
617             return NOT_ON_VAL;
618         }
619
620         sel = (ascsr >> 1) & 0x3;
621         if (sel == 0) {
622             ret_val = (2 * pll_clock(sel)) / (clock_peri_divider(CSI_BAUD));
623         } else if (sel == 1) {
624             sel++;
625             ret_val = (2 * pll_clock(sel)) / (clock_peri_divider(CSI_BAUD));;
626         } else if (sel == 2) {
627             ret_val = (2 * FREQ_CKIH_26M) / (clock_peri_divider(CSI_BAUD));
628         }
629         // Don't forget to double the divider
630         break;
631     }
632
633     return ret_val;
634 }
635 #if 0
636 RedBoot_cmd("ckoh",
637             "Select clock source for CKOH (J9 on CPU daughter card)",
638             " Default is 1/10 of ARM core\n\
639           <0> - display current ckoh selection \n\
640           <1> - ap_uncorrected_pat_ref_clk \n\
641           <2> - ungated_ap_clk (ARM Core in normal case) \n\
642           <3> - ungated_ap_ahb_clk (AHB) \n\
643           <4> - ungated_ap_pclk (IPG) \n\
644           <5> - usb_clk \n\
645           <6> - ap_perclk (baud clock) \n\
646           <7> - ap_ckil_clk (sync) \n\
647           <8> - ap_pat_ref_clk (ungated sync) \n\
648           <<The following only valid for Rev2.0 silicon and above>> \n\
649           <9> - crm_ap_nfc_clk \n\
650           <10> - ap_async_pat_ref_clk for EL1T and MQSPI \n\
651           <11> - ap_sdhc1_perclk \n\
652           <12> - ap_ahb_div2_clk (for SAHARA) \n\
653           <13> - ipu_lpmc_hsp_clk\n",
654             ckoh
655            );
656
657 static u8* div_str[] = {
658     "1/2 of ",
659     "1/3 of ",
660     "1/4 of ",
661     "1/5 of ",
662     "1/6 of ",
663     "1/8 of ",
664     "1/10 of ",
665     "1/12 of ",
666     "",
667     "",
668     "",
669     "",
670     "",
671     "",
672     "",
673     "",
674 };
675
676 static u8* ckoh_name[] ={
677     "NULL",
678     "ap_uncorrected_pat_ref_clk",
679     "ungated_ap_clk (ARM Core in normal case)",
680     "ungated_ap_ahb_clk (AHB)",
681     "ungated_ap_pclk (IPG)",
682     "usb_clk",
683     "ap_perclk (baud clock)",
684     "ap_ckil_clk (sync)",
685     "ap_pat_ref_clk (ungated sync)",
686     "crm_ap_nfc_clk",
687     "ap_async_pat_ref_clk for EL1T and MQSPI",
688     "ap_sdhc1_perclk",
689     "ap_ahb_div2_clk (for SAHARA)",
690     "ipu_lpmc_hsp_clk",
691 };
692
693 #define CKOH_MAX_INDEX          (sizeof(ckoh_name) / sizeof(u8*))
694 #define CKOH_DIV                6  // default divide by 10
695
696 extern u32 system_rev;
697
698 static void ckoh(int argc,char *argv[])
699 {
700     u32 action = 0, val, new_val, div = 0x8, i;
701
702     if (!scan_opts(argc, argv, 1, 0, 0, (void*) &action,
703                    OPTION_ARG_TYPE_NUM, "action"))
704         return;
705
706     if (action >= CKOH_MAX_INDEX ||
707         (system_rev == CHIP_REV_1_0 && action > 8)) {
708         diag_printf("%d is not supported\n\n", action);
709         return;
710     }
711
712     val = readl(CRM_AP_BASE_ADDR + CRM_AP_ACR);
713
714     if (action != 0) {
715         // set CKOHDIV to be 6 for dividing by 10
716         if (action == 2 || action == 3)
717             div = CKOH_DIV;
718         action--;
719         // clear CKOHS-HIGH, CKOHD, CHOHS, CKOHDIV bits and
720         new_val = (val & (~(1 << 18 | 0xFF00))) | (div << 8);
721         if (action > 7) {
722             new_val |= (1 << 18) | ((action & 7) << 12);
723         } else {
724             new_val |= action << 12;
725         }
726         writel(new_val, CRM_AP_BASE_ADDR + CRM_AP_ACR);
727         diag_printf("\nSet ckoh to ");
728     }
729
730     val = readl(CRM_AP_BASE_ADDR + CRM_AP_ACR);
731     /* locate the index in the name table */
732     new_val = ((val >> 15) & 8) | ((val >> 12) & 7);
733     i = (val >> 8) & 0xF;
734     diag_printf("%s%s\n", div_str[i], ckoh_name[new_val + 1]);
735     diag_printf("ACR register[0x%x]=0x%x\n\n",
736                 (CRM_AP_BASE_ADDR + CRM_AP_ACR), val);
737 }
738
739 RedBoot_cmd("ckol",
740             "Select clock source for CKO (J10 on EVB CPU card)",
741             " Default is CKIL\n\
742           <0> - display current cko selection\n\
743           <1> - ckil \n\
744           <2> - ap_pat_ref_clk (ungated sync) \n\
745           <3> - ap_ref_x2_clk \n\
746           <4} - ssi1_clk \n\
747           <5> - cs_clk \n\
748           <6> - RESERVED \n\
749           <7> - RESERVED \n\
750           <<The following only valid for Rev2.0 silicon and above>> \n\
751           <8> - dfm_ckil_multiply_clk \n\
752           <9> - ap_sdhc2_perclk \n",
753             ckol
754            );
755
756 static u8* cko_name[] ={
757     "NULL",
758     "ckil",
759     "ap_pat_ref_clk (ungated sync)",
760     "ap_ref_x2_clk",
761     "ssi1_clk",
762     "cs_clk",
763     "RESERVED",
764     "RESERVED",
765     "dfm_ckil_multiply_clk",
766     "ap_sdhc2_perclk",
767 };
768
769 #define CKO_MAX_INDEX           (sizeof(cko_name) / sizeof(u8*))
770
771 static void ckol(int argc,char *argv[])
772 {
773     u32 action = 0, val, new_val, t;
774
775     if (!scan_opts(argc, argv, 1, 0, 0, (void*) &action,
776                    OPTION_ARG_TYPE_NUM, "action"))
777         return;
778
779     if (action >= CKO_MAX_INDEX ||
780         (system_rev == CHIP_REV_1_0 && action > 6) ||
781         (action >= 7 && action <= 8)) {
782         diag_printf("%d is not supported\n\n", action);
783         return;
784     }
785
786     val = readl(CRM_AP_BASE_ADDR + CRM_AP_ACR);
787
788     if (action != 0) {
789         // turn on these clocks
790         switch (action) {
791         case 4: //SSI1
792             t = readl(CRM_AP_BASE_ADDR + CRM_AP_ACDER1);
793             writel(t | (1 << 6), CRM_AP_BASE_ADDR + CRM_AP_ACDER1);
794             break;
795         case 5: //SSI2
796             t = readl(CRM_AP_BASE_ADDR + CRM_AP_ACDER1);
797             writel(t | (1 << 14), CRM_AP_BASE_ADDR + CRM_AP_ACDER1);
798             break;
799         case 6: //cs_clk
800             t = readl(CRM_AP_BASE_ADDR + CRM_AP_ACDER1);
801             writel(t | (1 << 30), CRM_AP_BASE_ADDR + CRM_AP_ACDER1);
802             break;
803
804         }
805         action--;
806         /* clear CKOS-HIGH, CKOD, CHOS bits and */
807         new_val = val & (~((1 << 16) | 0xF0));
808         if (action > 5) {
809             new_val |= (1 << 16) | ((action & 7) << 4);
810         } else {
811             new_val |= action << 4;
812         }
813         writel(new_val, CRM_AP_BASE_ADDR + CRM_AP_ACR);
814         diag_printf("\nSet cko to ");
815     }
816
817     val = readl(CRM_AP_BASE_ADDR + CRM_AP_ACR);
818     /* locate the index in the name table */
819     new_val = ((val >> 13) & 8) | ((val >> 4) & 7);
820
821     diag_printf("%s\nACR register[0x%x]=0x%x\n\n", cko_name[new_val + 1],
822                 (CRM_AP_BASE_ADDR + CRM_AP_ACR), val);
823 }
824 #endif
825
826 /* Comment out the fuse setting commands for now */
827 #define IIM_ERR_SHIFT       8
828 #define POLL_FUSE_PRGD      (IIM_STAT_PRGD | (IIM_ERR_PRGE << IIM_ERR_SHIFT))
829 #define POLL_FUSE_SNSD      (IIM_STAT_SNSD | (IIM_ERR_SNSE << IIM_ERR_SHIFT))
830
831 static void fuse_op_start(void)
832 {
833     /* Do not generate interrupt */
834     writel(0, IIM_BASE_ADDR + IIM_STATM_OFF);
835     // clear the status bits and error bits
836     writel(0x3, IIM_BASE_ADDR + IIM_STAT_OFF);
837     writel(0xFE, IIM_BASE_ADDR + IIM_ERR_OFF);
838 }
839
840 /*
841  * The action should be either:
842  *          POLL_FUSE_PRGD
843  * or:
844  *          POLL_FUSE_SNSD
845  */
846 static int poll_fuse_op_done(int action)
847 {
848
849     u32 status, error;
850
851     if (action != POLL_FUSE_PRGD && action != POLL_FUSE_SNSD) {
852         diag_printf("%s(%d) invalid operation\n", __FUNCTION__, action);
853         return -1;
854     }
855
856     /* Poll busy bit till it is NOT set */
857     while ((readl(IIM_BASE_ADDR + IIM_STAT_OFF) & IIM_STAT_BUSY) != 0 ) {
858     }
859
860     /* Test for successful write */
861     status = readl(IIM_BASE_ADDR + IIM_STAT_OFF);
862     error = readl(IIM_BASE_ADDR + IIM_ERR_OFF);
863
864     if ((status & action) != 0 && (error & (action >> IIM_ERR_SHIFT)) == 0) {
865         if (error) {
866             diag_printf("Even though the operation seems successful...\n");
867             diag_printf("There are some error(s) at addr=0x%x: 0x%x\n",
868                         (IIM_BASE_ADDR + IIM_ERR_OFF), error);
869         }
870             return 0;
871         }
872     diag_printf("%s(%d) failed\n", __FUNCTION__, action);
873     diag_printf("status address=0x%x, value=0x%x\n",
874                 (IIM_BASE_ADDR + IIM_STAT_OFF), status);
875     diag_printf("There are some error(s) at addr=0x%x: 0x%x\n",
876                 (IIM_BASE_ADDR + IIM_ERR_OFF), error);
877     return -1;
878 }
879
880 static void sense_fuse(int bank, int row, int bit)
881 {
882     int addr, addr_l, addr_h, reg_addr;
883
884     fuse_op_start();
885
886     addr = ((bank << 11) | (row << 3) | (bit & 0x7));
887     /* Set IIM Program Upper Address */
888     addr_h = (addr >> 8) & 0x000000FF;
889     /* Set IIM Program Lower Address */
890     addr_l = (addr & 0x000000FF);
891
892 #ifdef IIM_FUSE_DEBUG
893     diag_printf("%s: addr_h=0x%x, addr_l=0x%x\n",
894                 __FUNCTION__, addr_h, addr_l);
895 #endif
896     writel(addr_h, IIM_BASE_ADDR + IIM_UA_OFF);
897     writel(addr_l, IIM_BASE_ADDR + IIM_LA_OFF);
898     /* Start sensing */
899     writel(0x8, IIM_BASE_ADDR + IIM_FCTL_OFF);
900     if (poll_fuse_op_done(POLL_FUSE_SNSD) != 0) {
901         diag_printf("%s(bank: %d, row: %d, bit: %d failed\n",
902                     __FUNCTION__, bank, row, bit);
903     }
904     reg_addr = IIM_BASE_ADDR + IIM_SDAT_OFF;
905     diag_printf("fuses at (bank:%d, row:%d) = 0x%x\n", bank, row, readl(reg_addr));
906 }
907
908 void do_fuse_read(int argc, char *argv[])
909 {
910     int bank, row;
911
912     if (argc == 1) {
913         diag_printf("Useage: fuse_read <bank> <row>\n");
914         return;
915     } else if (argc == 3) {
916         if (!parse_num(*(&argv[1]), (unsigned long *)&bank, &argv[1], " ")) {
917                 diag_printf("Error: Invalid parameter\n");
918             return;
919         }
920         if (!parse_num(*(&argv[2]), (unsigned long *)&row, &argv[2], " ")) {
921                 diag_printf("Error: Invalid parameter\n");
922                 return;
923             }
924
925         diag_printf("Read fuse at bank:%d row:%d\n", bank, row);
926         sense_fuse(bank, row, 0);
927
928     } else {
929         diag_printf("Passing in wrong arguments: %d\n", argc);
930         diag_printf("Useage: fuse_read <bank> <row>\n");
931     }
932 }
933
934 /* Blow fuses based on the bank, row and bit positions (all 0-based)
935 */
936 static int fuse_blow(int bank,int row,int bit)
937 {
938     int addr, addr_l, addr_h, ret = -1;
939
940     fuse_op_start();
941
942     /* Disable IIM Program Protect */
943     writel(0xAA, IIM_BASE_ADDR + IIM_PREG_P_OFF);
944
945     addr = ((bank << 11) | (row << 3) | (bit & 0x7));
946     /* Set IIM Program Upper Address */
947     addr_h = (addr >> 8) & 0x000000FF;
948     /* Set IIM Program Lower Address */
949     addr_l = (addr & 0x000000FF);
950
951 #ifdef IIM_FUSE_DEBUG
952     diag_printf("blowing addr_h=0x%x, addr_l=0x%x\n", addr_h, addr_l);
953 #endif
954
955     writel(addr_h, IIM_BASE_ADDR + IIM_UA_OFF);
956     writel(addr_l, IIM_BASE_ADDR + IIM_LA_OFF);
957     /* Start Programming */
958     writel(0x31, IIM_BASE_ADDR + IIM_FCTL_OFF);
959     if (poll_fuse_op_done(POLL_FUSE_PRGD) == 0) {
960         ret = 0;
961     }
962
963     /* Enable IIM Program Protect */
964     writel(0x0, IIM_BASE_ADDR + IIM_PREG_P_OFF);
965     return ret;
966 }
967
968 /*
969  * This command is added for burning IIM fuses
970  */
971 RedBoot_cmd("fuse_read",
972             "read some fuses",
973             "<bank> <row>",
974             do_fuse_read
975            );
976
977 RedBoot_cmd("fuse_blow",
978             "blow some fuses",
979             "<bank> <row> <value>",
980             do_fuse_blow
981            );
982
983 #define         INIT_STRING              "12345678"
984 static char ready_to_blow[] = INIT_STRING;
985
986 void quick_itoa(u32 num, char *a)
987 {
988     int i, j, k;
989     for (i = 0; i <= 7; i++) {
990         j = (num >> (4 * i)) & 0xF;
991         k = (j < 10) ? '0' : ('a' - 0xa);
992         a[i] = j + k;
993     }
994 }
995
996 void do_fuse_blow(int argc, char *argv[])
997 {
998     int bank, row, value, i;
999
1000     if (argc == 1) {
1001         diag_printf("It is too dangeous for you to use this command.\n");
1002         return;
1003     } else if (argc == 2) {
1004         if (strcasecmp(argv[1], "nandboot") == 0) {
1005             quick_itoa(readl(EPIT_BASE_ADDR + EPITCNR), ready_to_blow);
1006             diag_printf("%s\n", ready_to_blow);
1007         }
1008         return;
1009     } else if (argc == 3) {
1010         if (strcasecmp(argv[1], "nandboot") == 0 &&
1011             strcasecmp(argv[2], ready_to_blow) == 0) {
1012             diag_printf("Ready to burn NAND boot fuses\n");
1013             if ((fuse_blow(0, 3, 2) != 0) || (fuse_blow(0, 4, 2) != 0) || (fuse_blow(0, 5, 1) != 0)) {
1014             //if (fuse_blow(0, 5, 1) != 0) {
1015                 diag_printf("NAND BOOT fuse blown failed miserably ...\n");
1016             } else {
1017                 diag_printf("NAND BOOT fuse blown successfully ...\n");
1018             }
1019         } else {
1020             diag_printf("Not ready: %s, %s\n", argv[1], argv[2]);
1021         }
1022     } else if (argc == 4) {
1023         if (!parse_num(*(&argv[1]), (unsigned long *)&bank, &argv[1], " ")) {
1024                 diag_printf("Error: Invalid parameter\n");
1025             return;
1026         }
1027         if (!parse_num(*(&argv[2]), (unsigned long *)&row, &argv[2], " ")) {
1028                 diag_printf("Error: Invalid parameter\n");
1029                 return;
1030             }
1031         if (!parse_num(*(&argv[3]), (unsigned long *)&value, &argv[3], " ")) {
1032                 diag_printf("Error: Invalid parameter\n");
1033                 return;
1034             }
1035
1036         diag_printf("Blowing fuse at bank:%d row:%d value:%d\n",
1037                     bank, row, value);
1038         for (i = 0; i < 8; i++) {
1039             if (((value >> i) & 0x1) == 0) {
1040                 continue;
1041             }
1042             if (fuse_blow(bank, row, i) != 0) {
1043                 diag_printf("fuse_blow(bank: %d, row: %d, bit: %d failed\n",
1044                             bank, row, i);
1045             } else {
1046                 diag_printf("fuse_blow(bank: %d, row: %d, bit: %d successful\n",
1047                             bank, row, i);
1048             }
1049         }
1050         sense_fuse(bank, row, 0);
1051
1052     } else {
1053         diag_printf("Passing in wrong arguments: %d\n", argc);
1054     }
1055     /* Reset to default string */
1056     strcpy(ready_to_blow, INIT_STRING);;
1057 }
1058
1059 /* precondition: m>0 and n>0.  Let g=gcd(m,n). */
1060 int gcd(int m, int n)
1061 {
1062     int t;
1063     while(m > 0) {
1064         if(n > m) {t = m; m = n; n = t;} /* swap */
1065         m -= n;
1066     }
1067     return n;
1068  }