]> git.karo-electronics.de Git - karo-tx-redboot.git/blob - packages/hal/arm/mx53/var/v2_0/src/cmds.c
TX53 Release 2011-12-20
[karo-tx-redboot.git] / packages / hal / arm / mx53 / 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 #include CYGBLD_HAL_PLF_DEFS_H
47
48 #include "hab_super_root.h"
49
50 #ifndef FUSE_PROG_START
51 #define FUSE_PROG_START()               CYG_EMPTY_STATEMENT
52 #define FUSE_PROG_DONE()                CYG_EMPTY_STATEMENT
53 #endif
54
55 //#define IIM_FUSE_DEBUG
56 //#define CMD_CLOCK_DEBUG
57 #ifdef CMD_CLOCK_DEBUG
58 static int dbg_enable;
59
60 #define enable_dbg()            \
61   CYG_MACRO_START                       \
62   dbg_enable = 1;                       \
63   CYG_MACRO_END
64
65 #define dbg(fmt...)                                                             \
66   CYG_MACRO_START                                                               \
67   if (dbg_enable)                                                               \
68           diag_printf(fmt);                                                     \
69   CYG_MACRO_END
70 #else
71 #define dbg_enable 0
72 #define enable_dbg()            CYG_EMPTY_STATEMENT
73 #define dbg(fmt...)             CYG_EMPTY_STATEMENT
74 #endif
75
76 static int gcd(int m, int n);
77
78 typedef unsigned long long      u64;
79 typedef unsigned int            u32;
80 typedef unsigned short          u16;
81 typedef unsigned char           u8;
82
83 #define SZ_DEC_1M               1000000
84 #define PLL_PD_MAX              16              //actual pd+1
85 #define PLL_MFI_MAX             15
86 #define PLL_MFI_MIN             5
87 #define ARM_DIV_MAX             8
88 #define IPG_DIV_MAX             4
89 #define AHB_DIV_MAX             8
90 #define EMI_DIV_MAX             8
91 #define NFC_DIV_MAX             8
92
93 struct pll_param {
94         u32 pd;
95         u32 mfi;
96         u32 mfn;
97         u32 mfd;
98 };
99
100 #define PLL_FREQ_MAX(_ref_clk_)    (4 * _ref_clk_ * PLL_MFI_MAX)
101 #define PLL_FREQ_MIN(_ref_clk_)    ((2 * _ref_clk_ * (PLL_MFI_MIN - 1)) / PLL_PD_MAX)
102 #define MAX_DDR_CLK             400000000
103 #define AHB_CLK_MAX             133333333
104 #define IPG_CLK_MAX             (AHB_CLK_MAX / 2)
105 #define NFC_CLK_MAX             25000000
106 // IPU-HSP clock is independent of the HCLK and can go up to 177MHz but requires
107 // higher voltage support. For simplicity, limit it to 133MHz
108 #define HSP_CLK_MAX             133333333
109
110 #define ERR_WRONG_CLK   (-1)
111 #define ERR_NO_MFI              (-2)
112 #define ERR_NO_MFN              (-3)
113 #define ERR_NO_PD               (-4)
114 #define ERR_NO_PRESC    (-5)
115 #define ERR_NO_AHB_DIV  (-6)
116
117 u32 pll_clock(enum plls pll);
118 u32 get_main_clock(enum main_clocks clk);
119 u32 get_peri_clock(enum peri_clocks clk);
120
121 static volatile u32 *pll_base[] =
122 {
123         &REG32(PLL1_BASE_ADDR),
124         &REG32(PLL2_BASE_ADDR),
125         &REG32(PLL3_BASE_ADDR),
126         &REG32(PLL4_BASE_ADDR),
127 };
128
129 static void clock_setup(int argc, char *argv[]);
130
131 RedBoot_cmd("clock",
132                         "Setup/Display clock\nSyntax:",
133                         "[<core clock in MHz> :<DDR clock in MHz>]\n\n"
134                         "   Examples:\n"
135                         "   [clock]         -> Show various clocks\n"
136                         "   [clock 665]     -> Core=665\n"
137                         "   [clock 800:133] -> Core=800 DDR=133\n"
138                         "   [clock :166]    -> Core=no change DDR=166\n",
139                         clock_setup
140         );
141
142 /*!
143  * This is to calculate various parameters based on reference clock and
144  * targeted clock based on the equation:
145  *      t_clk = 2*ref_freq*(mfi + mfn/(mfd+1))/(pd+1)
146  * This calculation is based on a fixed MFD value for simplicity.
147  *
148  * @param ref       reference clock freq in Hz
149  * @param target    targeted clock in Hz
150  * @param p_pd      calculated pd value (pd value from register + 1) upon return
151  * @param p_mfi     calculated actual mfi value upon return
152  * @param p_mfn     calculated actual mfn value upon return
153  * @param p_mfd     fixed mfd value (mfd value from register + 1) upon return
154  *
155  * @return          0 if successful; non-zero otherwise.
156  */
157 int calc_pll_params(u32 ref, u32 target, struct pll_param *pll)
158 {
159         int pd, mfi = 1, mfn, mfd, i;
160         u64 n_target = target, n_ref = ref;
161
162         // make sure targeted freq is in the valid range. Otherwise the
163         // following calculation might be wrong!!!
164         if (n_target < PLL_FREQ_MIN(ref) || n_target > PLL_FREQ_MAX(ref))
165                 return ERR_WRONG_CLK;
166
167         mfd = 24 * 16;
168
169         // Use n_target and n_ref to avoid overflow
170         for (pd = 1; pd <= PLL_PD_MAX; pd++) {
171                 mfi = (n_target * pd) / (4 * n_ref);
172                 if (mfi > PLL_MFI_MAX) {
173                         return ERR_NO_MFI;
174                 } else if (mfi < 5) {
175                         continue;
176                 }
177                 break;
178         }
179         // Now got pd and mfi already
180         mfn = (((n_target * pd) / 4 - n_ref * mfi) * mfd) / n_ref;
181
182         dbg("%d: ref=%d, target=%d, pd=%d, mfi=%d,mfn=%d, mfd=%d\n",
183                 __LINE__, ref, target, pd, mfi, mfn, mfd);
184
185         i = 1;
186         if (mfn != 0)
187                 i = gcd(mfd, mfn);
188         pll->pd = pd;
189         pll->mfi = mfi;
190         pll->mfn = mfn / i;
191         pll->mfd = mfd / i;
192         return 0;
193 }
194
195 /*!
196  * This function returns the low power audio clock.
197  */
198 u32 get_lp_apm(void)
199 {
200         u32 ret_val;
201         u32 ccsr = readl(CCM_BASE_ADDR + CLKCTL_CCSR);
202
203         if (((ccsr >> 9) & 1) == 0) {
204                 ret_val = FREQ_24MHZ;
205         } else {
206                 ret_val = FREQ_32768HZ;
207         }
208         dbg("%s: CCSR[%08lx]=%08x freq=%u.%03uMHz\n", __FUNCTION__,
209                 CCM_BASE_ADDR + CLKCTL_CCSR, ccsr, ret_val / 1000000, ret_val / 1000 % 1000);
210         return ret_val;
211 }
212
213 /*!
214  * This function returns the periph_clk.
215  */
216 u32 get_periph_clk(void)
217 {
218         u32 ret_val, clk_sel;
219
220         u32 cbcdr = readl(CCM_BASE_ADDR + CLKCTL_CBCDR);
221         u32 cbcmr = readl(CCM_BASE_ADDR + CLKCTL_CBCMR);
222
223         if (!(cbcdr & (1 << 25))) {
224                 ret_val = pll_clock(PLL2);
225                 dbg("%s: CBCDR[%08lx]=%08x CBCMR[%08lx]=%08x freq=%u.%03uMHz\n", __FUNCTION__,
226                         CCM_BASE_ADDR + CLKCTL_CBCDR, cbcdr,
227                         CCM_BASE_ADDR + CLKCTL_CBCMR, cbcmr,
228                         ret_val / 1000000, ret_val / 1000 % 1000);
229         } else {
230                 clk_sel = (cbcmr >> 12) & 3;
231                 if (clk_sel == 0) {
232                         ret_val = pll_clock(PLL1);
233                 } else if (clk_sel == 1) {
234                         ret_val = pll_clock(PLL3);
235                 } else if (clk_sel == 2) {
236                         ret_val = get_lp_apm();
237                 } else {
238                         diag_printf("Invalid CBCMR[CLK_SEL]: %d\n", clk_sel);
239                         return ERR_WRONG_CLK;
240                 }
241                 dbg("%s: CBCDR[%08lx]=%08x CBCMR[%08lx]=%08x clk_sel=%d freq=%u.%03uMHz\n", __FUNCTION__,
242                         CCM_BASE_ADDR + CLKCTL_CBCDR, cbcdr,
243                         CCM_BASE_ADDR + CLKCTL_CBCMR, cbcmr,
244                         clk_sel, ret_val / 1000000, ret_val / 1000 % 1000);
245         }
246         return ret_val;
247 }
248
249 /*!
250  * This function assumes the expected core clock has to be changed by
251  * modifying the PLL. This is NOT true always but for most of the times,
252  * it is. So it assumes the PLL output freq is the same as the expected
253  * core clock (presc=1) unless the core clock is less than PLL_FREQ_MIN.
254  * In the latter case, it will try to increase the presc value until
255  * (presc*core_clk) is greater than PLL_FREQ_MIN. It then makes call to
256  * calc_pll_params() and obtains the values of PD, MFI,MFN, MFD based
257  * on the targeted PLL and reference input clock to the PLL. Lastly,
258  * it sets the register based on these values along with the dividers.
259  * Note 1) There is no value checking for the passed-in divider values
260  *         so the caller has to make sure those values are sensible.
261  *      2) Also adjust the NFC divider such that the NFC clock doesn't
262  *         exceed NFC_CLK_MAX.
263  *      3) IPU HSP clock is independent of AHB clock. Even it can go up to
264  *         177MHz for higher voltage, this function fixes the max to 133MHz.
265  *      4) This function should not have allowed diag_printf() calls since
266  *         the serial driver has been stopped. But leave then here to allow
267  *         easy debugging by NOT calling the cyg_hal_plf_serial_stop().
268  *
269  * @param ref       pll input reference clock (24MHz)
270  * @param core_clk  core clock in Hz
271  * @param emi_clk   emi clock in Hz
272  # @return          0 if successful; non-zero otherwise
273  */
274 int configure_clock(u32 ref, u32 core_clk, u32 emi_clk)
275 {
276         u32 pll, clk_src;
277         struct pll_param pll_param;
278         int ret, clk_sel, div = 1, div_core = 1, div_per = 1, shift = 0;
279         u32 cbcdr = readl(CCM_BASE_ADDR + CLKCTL_CBCDR);
280         u32 cbcmr = readl(CCM_BASE_ADDR + CLKCTL_CBCMR);
281         u32 ccsr = readl(CCM_BASE_ADDR + CLKCTL_CCSR);
282         u32 icgc = readl(PLATFORM_BASE_ADDR + PLATFORM_ICGC);
283
284         dbg("%s: cbcdr[%08lx]=%08x\n", __FUNCTION__,
285                 CCM_BASE_ADDR + CLKCTL_CBCDR, cbcdr);
286         dbg("%s: cbcmr[%08lx]=%08x\n", __FUNCTION__,
287                 CCM_BASE_ADDR + CLKCTL_CBCMR, cbcdr);
288         dbg("%s: ccsr[%08lx]=%08x\n", __FUNCTION__,
289                 CCM_BASE_ADDR + CLKCTL_CCSR, cbcdr);
290         dbg("%s: icgc[%08lx]=%08x\n", __FUNCTION__,
291                 PLATFORM_BASE_ADDR + PLATFORM_ICGC, icgc);
292
293         if (core_clk != 0) {
294                 // assume pll default to core clock first
295                 pll = core_clk;
296                 if ((ret = calc_pll_params(ref, pll, &pll_param)) != 0) {
297                         diag_printf("can't find pll parameters: %d\n", ret);
298                         return ret;
299                 }
300
301                 dbg("%s: ref=%d, pll=%d, pd=%d, mfi=%d,mfn=%d, mfd=%d\n", __FUNCTION__,
302                         ref, pll, pll_param.pd, pll_param.mfi, pll_param.mfn, pll_param.mfd);
303
304                 /* Applies for TO 2 only */
305                 if (((cbcdr >> 30) & 0x1) == 0x1) {
306                         /* Disable IPU and HSC dividers */
307                         writel(0x60000, CCM_BASE_ADDR + CLKCTL_CCDR);
308                         /* Switch DDR to different source */
309                         writel(cbcdr & ~0x40000000, CCM_BASE_ADDR + CLKCTL_CBCDR);
310                         while (readl(CCM_BASE_ADDR + CLKCTL_CDHIPR) != 0);
311                         writel(0x0, CCM_BASE_ADDR + CLKCTL_CCDR);
312                 }
313
314                 /* Switch ARM to PLL2 clock */
315                 writel(ccsr | 0x4, CCM_BASE_ADDR + CLKCTL_CCSR);
316
317                 if ((core_clk > 665000000) && (core_clk <= 800000000)) {
318                         div_per = 5;
319                 } else if (core_clk > 800000000) {
320                         div_per = 6;
321                 } else {
322                         div_per = 4;
323                 }
324
325                 if (core_clk > 800000000) {
326                         div_core = 3;
327                         increase_core_voltage(true);
328                 } else {
329                         div_core = 2;
330                         increase_core_voltage(false);
331                 }
332                 cyg_hal_plf_serial_stop();
333
334                 // adjust pll settings
335                 writel(((pll_param.pd - 1) << 0) | (pll_param.mfi << 4),
336                         PLL1_BASE_ADDR + PLL_DP_OP);
337                 writel(pll_param.mfn, PLL1_BASE_ADDR + PLL_DP_MFN);
338                 writel(pll_param.mfd - 1, PLL1_BASE_ADDR + PLL_DP_MFD);
339                 writel(((pll_param.pd - 1) << 0) | (pll_param.mfi << 4),
340                         PLL1_BASE_ADDR + PLL_DP_HFS_OP);
341                 writel(pll_param.mfn, PLL1_BASE_ADDR + PLL_DP_HFS_MFN);
342                 writel(pll_param.mfd - 1, PLL1_BASE_ADDR + PLL_DP_HFS_MFD);
343
344                 icgc &= ~0x77;
345                 icgc |= div_core << 4;
346                 icgc |= div_per;
347                 /* Set the platform clock dividers */
348                 writel(icgc, PLATFORM_BASE_ADDR + PLATFORM_ICGC);
349                 /* Switch ARM back to PLL1 */
350                 writel((ccsr & ~0x4), CCM_BASE_ADDR + CLKCTL_CCSR);
351                 /* Applies for TO 2 only */
352                 if (((cbcdr >> 30) & 0x1) == 0x1) {
353                         /* Disable IPU and HSC dividers */
354                         writel(0x60000, CCM_BASE_ADDR + CLKCTL_CCDR);
355                         /* Switch DDR back to PLL1 */
356                         writel(cbcdr | 0x40000000, CCM_BASE_ADDR + CLKCTL_CBCDR);
357                         while (readl(CCM_BASE_ADDR + CLKCTL_CDHIPR) != 0);
358                         writel(0x0, CCM_BASE_ADDR + CLKCTL_CCDR);
359                         if (emi_clk == 0) {
360                                 /* Keep EMI clock to the max if not specified */
361                                 emi_clk = 200000000;
362                         }
363                 }
364                 cyg_hal_plf_serial_init();
365         }
366
367         if (emi_clk != 0) {
368                 /* Applies for TO 2 only */
369                 if (((cbcdr >> 30) & 0x1) == 0x1) {
370                         clk_src = pll_clock(PLL1);
371                         shift = 27;
372                 } else {
373                         clk_src = get_periph_clk();
374                         /* Find DDR clock input */
375                         clk_sel = (cbcmr >> 10) & 0x3;
376                         if (clk_sel == 0) {
377                                 shift = 16;
378                         } else if (clk_sel == 1) {
379                                 shift = 19;
380                         } else if (clk_sel == 2) {
381                                 shift = 22;
382                         } else if (clk_sel == 3) {
383                                 shift = 10;
384                         }
385                 }
386                 if ((clk_src % emi_clk) == 0)
387                         div = clk_src / emi_clk;
388                 else
389                         div = (clk_src / emi_clk) + 1;
390                 if (div > 8)
391                         div = 8;
392
393                 cbcdr &= ~(0x7 << shift);
394                 cbcdr |= (div - 1) << shift;
395
396                 dbg("%s@%d: \n", __FUNCTION__, __LINE__);
397
398                 /* Disable IPU and HSC dividers */
399                 writel(0x60000, CCM_BASE_ADDR + CLKCTL_CCDR);
400                 writel(cbcdr, CCM_BASE_ADDR + CLKCTL_CBCDR);
401                 while (readl(CCM_BASE_ADDR + CLKCTL_CDHIPR) != 0);
402                 writel(0x0, CCM_BASE_ADDR + CLKCTL_CCDR);
403         }
404         return 0;
405 }
406
407 static void clock_setup(int argc,char *argv[])
408 {
409         u32 i, core_clk, ddr_clk, data[3];
410         unsigned long temp;
411         int ret;
412
413         if (argc == 1)
414                 goto print_clock;
415
416         enable_dbg();
417         for (i = 0; i < 2; i++) {
418                 if (!parse_num(argv[1], &temp, &argv[1], ":")) {
419                         diag_printf("Error: Invalid parameter\n");
420                         return;
421                 }
422                 data[i] = temp;
423         }
424
425         core_clk = data[0] * SZ_DEC_1M;
426         ddr_clk = data[1] * SZ_DEC_1M;
427
428         if (core_clk != 0) {
429                 if ((core_clk < PLL_FREQ_MIN(PLL_REF_CLK)) || (core_clk > PLL_FREQ_MAX(PLL_REF_CLK))) {
430                         diag_printf("Targeted core clock should be within [%d - %d]\n",
431                                                 PLL_FREQ_MIN(PLL_REF_CLK), PLL_FREQ_MAX(PLL_REF_CLK));
432                         return;
433                 }
434         }
435
436         if (ddr_clk != 0) {
437                 if (ddr_clk > MAX_DDR_CLK) {
438                         diag_printf("DDR clock should be less than %d MHz, assuming max value\n",
439                                                 MAX_DDR_CLK / SZ_DEC_1M);
440                         ddr_clk = MAX_DDR_CLK;
441                 }
442         }
443
444         // adjust the clock
445         ret = configure_clock(PLL_REF_CLK, core_clk, ddr_clk);
446         if (ret != 0) {
447                 diag_printf("Failed to setup clock: %d\n", ret);
448                 return;
449         }
450         diag_printf("\n<<<New clock setting>>>\n");
451
452         // Now printing clocks
453 print_clock:
454
455         diag_printf("\nPLL1\t\tPLL2\t\tPLL3\t\tPLL4\n");
456         diag_printf("========================================================\n");
457         diag_printf("%-16d%-16d%-16d%-16d\n\n", pll_clock(PLL1), pll_clock(PLL2),
458                                 pll_clock(PLL3), pll_clock(PLL4));
459         diag_printf("AXI_A\t\tAXI_B\t\tEMI_SLOW_CLK\n");
460         diag_printf("========================================================\n");
461         diag_printf("%-16d%-16d%-16d\n\n",
462                                 get_main_clock(AXI_A_CLK),
463                                 get_main_clock(AXI_B_CLK),
464                                 get_main_clock(EMI_SLOW_CLK));
465         diag_printf("CPU\t\tAHB\t\tIPG\t\tDDR_CLK\n");
466         diag_printf("========================================================\n");
467         diag_printf("%-16d%-16d%-16d%-16d\n\n",
468                                 get_main_clock(CPU_CLK),
469                                 get_main_clock(AHB_CLK),
470                                 get_main_clock(IPG_CLK),
471                                 get_main_clock(DDR_CLK));
472
473         diag_printf("NFC\t\tUSB\t\tIPG_PER_CLK\n");
474         diag_printf("========================================\n");
475         diag_printf("%-16d%-16d%-16d\n\n",
476                                 get_main_clock(NFC_CLK),
477                                 get_main_clock(USB_CLK),
478                                 get_main_clock(IPG_PER_CLK));
479
480         diag_printf("UART1-3\t\tSSI1\t\tSSI2\t\tSPI\n");
481         diag_printf("===========================================");
482         diag_printf("=============\n");
483
484         diag_printf("%-16d%-16d%-16d%-16d\n\n",
485                                 get_peri_clock(UART1_BAUD),
486                                 get_peri_clock(SSI1_BAUD),
487                                 get_peri_clock(SSI2_BAUD),
488                                 get_peri_clock(SPI1_CLK));
489
490 #if 0
491         diag_printf("IPG_PERCLK as baud clock for: UART1-5, I2C, OWIRE, SDHC");
492         if (((readl(EPIT1_BASE_ADDR) >> 24) & 0x3) == 0x2) {
493                 diag_printf(", EPIT");
494         }
495         if (((readl(GPT1_BASE_ADDR) >> 6) & 0x7) == 0x2) {
496                 diag_printf(", GPT");
497         }
498 #endif
499         diag_printf("\n");
500
501 }
502
503 /*!
504  * This function returns the PLL output value in Hz based on pll.
505  */
506 u32 pll_clock(enum plls pll)
507 {
508         u64 ref_clk;
509         u32 mfi, mfn, mfd, pdf, pll_out;
510         int sign;
511         u32 dp_ctrl, dp_op, dp_mfd, dp_mfn;
512         int clk_sel;
513         int dbl;
514
515         dp_ctrl = pll_base[pll][PLL_DP_CTL >> 2];
516         clk_sel = MXC_GET_FIELD(dp_ctrl, 2, 8);
517         ref_clk = PLL_REF_CLK;
518
519         dbg("clk_sel=%d\n", clk_sel);
520
521         if ((pll_base[pll][PLL_DP_CTL >> 2] & 0x80) == 0) {
522                 dp_op = pll_base[pll][PLL_DP_OP >> 2];
523                 dp_mfd = pll_base[pll][PLL_DP_MFD >> 2];
524                 dp_mfn = pll_base[pll][PLL_DP_MFN >> 2];
525         } else {
526                 dp_op = pll_base[pll][PLL_DP_HFS_OP >> 2];
527                 dp_mfd = pll_base[pll][PLL_DP_HFS_MFD >> 2];
528                 dp_mfn = pll_base[pll][PLL_DP_HFS_MFN >> 2];
529         }
530         pdf = dp_op & 0xF;
531         mfi = (dp_op >> 4) & 0xF;
532         mfi = (mfi <= 5) ? 5: mfi;
533         mfd = dp_mfd & 0x07FFFFFF;
534         mfn = dp_mfn & 0x07FFFFFF;
535
536         sign = (mfn < 0x4000000) ? 1 : -1;
537         mfn = (mfn < 0x4000000) ? mfn : (0x8000000 - mfn);
538
539         dbl = 2 * (((dp_ctrl >> 12) & 0x1) + 1);
540
541         dbg("%s: ref=%llu.%03lluMHz, dbl=%d, pd=%d, mfi=%d, mfn=%d, mfd=%d\n",
542                 __FUNCTION__, ref_clk / 1000000, ref_clk / 1000 % 1000,
543                 dbl, pdf + 1, mfi, sign * mfn, mfd + 1);
544
545         pll_out = (dbl * ref_clk * mfi + dbl * ref_clk * sign * mfn / (mfd + 1)) /
546                 (pdf + 1);
547
548         return pll_out;
549 }
550
551 /*!
552  * This function returns the emi_core_clk_root clock.
553  */
554 u32 get_emi_core_clk(void)
555 {
556         u32 cbcdr = readl(CCM_BASE_ADDR + CLKCTL_CBCDR);
557         u32 clk_sel, max_pdf, peri_clk, ahb_clk;
558         u32 ret_val;
559
560         max_pdf = (cbcdr >> 10) & 0x7;
561         peri_clk = get_periph_clk();
562         ahb_clk = peri_clk / (max_pdf + 1);
563
564         clk_sel = (cbcdr >> 26) & 1;
565         if (clk_sel == 0) {
566                 ret_val = peri_clk;
567         } else {
568                 ret_val = ahb_clk ;
569         }
570         dbg("%s: CBCDR[%08lx]=%08x freq=%u.%03uMHz\n", __FUNCTION__,
571                 CCM_BASE_ADDR + CLKCTL_CBCDR, cbcdr, ret_val / 1000000, ret_val / 1000 % 1000);
572         return ret_val;
573 }
574
575 /*!
576  * This function returns the main clock value in Hz.
577  */
578 u32 get_main_clock(enum main_clocks clk)
579 {
580         u32 pdf, max_pdf, ipg_pdf, nfc_pdf, clk_sel;
581         u32 pll, ret_val;
582         u32 cacrr = readl(CCM_BASE_ADDR + CLKCTL_CACRR);
583         u32 cbcdr = readl(CCM_BASE_ADDR + CLKCTL_CBCDR);
584         u32 cbcmr = readl(CCM_BASE_ADDR + CLKCTL_CBCMR);
585         u32 cscmr1 = readl(CCM_BASE_ADDR + CLKCTL_CSCMR1);
586         u32 cscdr1 = readl(CCM_BASE_ADDR + CLKCTL_CSCDR1);
587
588         dbg("%s: \n", __FUNCTION__);
589         switch (clk) {
590         case CPU_CLK:
591                 pdf = cacrr & 0x7;
592                 pll = pll_clock(PLL1);
593                 ret_val = pll / (pdf + 1);
594                 break;
595
596         case AHB_CLK:
597                 max_pdf = (cbcdr >> 10) & 0x7;
598                 pll = get_periph_clk();
599                 ret_val = pll / (max_pdf + 1);
600                 break;
601
602         case AXI_A_CLK:
603                 pdf = (cbcdr >> 16) & 0x7;
604                 pll = get_periph_clk();
605                 ret_val = pll / (pdf + 1);
606                 break;
607
608         case AXI_B_CLK:
609                 pdf = (cbcdr >> 19) & 0x7;
610                 pll = get_periph_clk();
611                 ret_val = pll / (pdf + 1);
612                 break;
613
614         case EMI_SLOW_CLK:
615                 pll = get_emi_core_clk();
616                 pdf = (cbcdr >> 22) & 0x7;
617                 ret_val = pll / (pdf + 1);
618                 break;
619
620         case IPG_CLK:
621                 max_pdf = (cbcdr >> 10) & 0x7;
622                 ipg_pdf = (cbcdr >> 8) & 0x3;
623                 pll = get_periph_clk();
624                 ret_val = pll / ((max_pdf + 1) * (ipg_pdf + 1));
625                 break;
626
627         case IPG_PER_CLK:
628                 clk_sel = cbcmr & 1;
629                 if (clk_sel == 0) {
630                         clk_sel = (cbcmr >> 1) & 1;
631                         pdf = (((cbcdr >> 6) & 3) + 1) * (((cbcdr >> 3) & 7) + 1) * ((cbcdr & 7) + 1);
632                         if (clk_sel == 0) {
633                                 ret_val = get_periph_clk() / pdf;
634                         } else {
635                                 ret_val = get_lp_apm();
636                         }
637                 } else {
638                         /* Same as IPG_CLK */
639                         max_pdf = (cbcdr >> 10) & 0x7;
640                         ipg_pdf = (cbcdr >> 8) & 0x3;
641                         pll = get_periph_clk();
642                         ret_val = pll / ((max_pdf + 1) * (ipg_pdf + 1));
643                 }
644                 break;
645
646         case DDR_CLK:
647                 clk_sel = (cbcmr >> 10) & 3;
648                 pll = get_periph_clk();
649                 if (clk_sel == 0) {
650                         /* AXI A */
651                         pdf = (cbcdr >> 16) & 0x7;
652                 } else if (clk_sel == 1) {
653                         /* AXI B */
654                         pdf = (cbcdr >> 19) & 0x7;
655                 } else if (clk_sel == 2) {
656                         /* EMI SLOW CLOCK ROOT */
657                         pll = get_emi_core_clk();
658                         pdf = (cbcdr >> 22) & 0x7;
659                 } else if (clk_sel == 3) {
660                         /* AHB CLOCK */
661                         pdf = (cbcdr >> 10) & 0x7;
662                 }
663
664                 ret_val = pll / (pdf + 1);
665                 break;
666
667         case NFC_CLK:
668                 pdf = (cbcdr >> 22) & 0x7;
669                 nfc_pdf = (cbcdr >> 13) & 0x7;
670                 pll = get_emi_core_clk();
671                 ret_val = pll / ((pdf + 1) * (nfc_pdf + 1));
672                 break;
673
674         case USB_CLK:
675                 clk_sel = (cscmr1 >> 22) & 3;
676                 if (clk_sel == 0) {
677                         pll = pll_clock(PLL1);
678                 } else if (clk_sel == 1) {
679                         pll = pll_clock(PLL2);
680                 } else if (clk_sel == 2) {
681                         pll = pll_clock(PLL3);
682                 } else if (clk_sel == 3) {
683                         pll = get_lp_apm();
684                 }
685                 pdf = (cscdr1 >> 8) & 0x7;
686                 max_pdf = (cscdr1 >> 6) & 0x3;
687                 ret_val = pll / ((pdf + 1) * (max_pdf + 1));
688                 break;
689
690         default:
691                 diag_printf("Unknown clock: %d\n", clk);
692                 return ERR_WRONG_CLK;
693         }
694
695         return ret_val;
696 }
697
698 /*!
699  * This function returns the peripheral clock value in Hz.
700  */
701 u32 get_peri_clock(enum peri_clocks clk)
702 {
703         u32 ret_val = 0, pdf, pre_pdf, clk_sel;
704         u32 cscmr1 = readl(CCM_BASE_ADDR + CLKCTL_CSCMR1);
705         u32 cscdr1 = readl(CCM_BASE_ADDR + CLKCTL_CSCDR1);
706         u32 cscdr2 = readl(CCM_BASE_ADDR + CLKCTL_CSCDR2);
707         u32 cs1cdr = readl(CCM_BASE_ADDR + CLKCTL_CS1CDR);
708         u32 cs2cdr = readl(CCM_BASE_ADDR + CLKCTL_CS2CDR);
709
710         dbg("%s: \n", __FUNCTION__);
711         switch (clk) {
712         case UART1_BAUD:
713         case UART2_BAUD:
714         case UART3_BAUD:
715                 pre_pdf = (cscdr1 >> 3) & 0x7;
716                 pdf = cscdr1 & 0x7;
717                 clk_sel = (cscmr1 >> 24) & 3;
718                 if (clk_sel == 0) {
719                         ret_val = pll_clock(PLL1) / ((pre_pdf + 1) * (pdf + 1));
720                 } else if (clk_sel == 1) {
721                         ret_val = pll_clock(PLL2) / ((pre_pdf + 1) * (pdf + 1));
722                 } else if (clk_sel == 2) {
723                         ret_val = pll_clock(PLL3) / ((pre_pdf + 1) * (pdf + 1));
724                 } else {
725                         ret_val = get_lp_apm() / ((pre_pdf + 1) * (pdf + 1));
726                 }
727                 break;
728         case SSI1_BAUD:
729                 pre_pdf = (cs1cdr >> 6) & 0x7;
730                 pdf = cs1cdr & 0x3F;
731                 clk_sel = (cscmr1 >> 14) & 3;
732                 if (clk_sel == 0) {
733                         ret_val = pll_clock(PLL1) / ((pre_pdf + 1) * (pdf + 1));
734                 } else if (clk_sel == 0x1) {
735                         ret_val = pll_clock(PLL2) / ((pre_pdf + 1) * (pdf + 1));
736                 } else if (clk_sel == 0x2) {
737                         ret_val = pll_clock(PLL3) / ((pre_pdf + 1) * (pdf + 1));
738                 } else {
739                         ret_val = CKIH /((pre_pdf + 1) * (pdf + 1));
740                 }
741                 break;
742         case SSI2_BAUD:
743                 pre_pdf = (cs2cdr >> 6) & 0x7;
744                 pdf = cs2cdr & 0x3F;
745                 clk_sel = (cscmr1 >> 12) & 3;
746                 if (clk_sel == 0) {
747                         ret_val = pll_clock(PLL1) / ((pre_pdf + 1) * (pdf + 1));
748                 } else if (clk_sel == 0x1) {
749                         ret_val = pll_clock(PLL2) / ((pre_pdf + 1) * (pdf + 1));
750                 } else if (clk_sel == 0x2) {
751                         ret_val = pll_clock(PLL3) / ((pre_pdf + 1) * (pdf + 1));
752                 } else {
753                         ret_val = CKIH /((pre_pdf + 1) * (pdf + 1));
754                 }
755                 break;
756         case SPI1_CLK:
757         case SPI2_CLK:
758                 pre_pdf = (cscdr2 >> 25) & 0x7;
759                 pdf = (cscdr2 >> 19) & 0x3F;
760                 clk_sel = (cscmr1 >> 4) & 3;
761                 if (clk_sel == 0) {
762                         ret_val = pll_clock(PLL1) / ((pre_pdf + 1) * (pdf + 1));
763                 } else if (clk_sel == 1) {
764                         ret_val = pll_clock(PLL2) / ((pre_pdf + 1) * (pdf + 1));
765                 } else if (clk_sel == 2) {
766                         ret_val = pll_clock(PLL3) / ((pre_pdf + 1) * (pdf + 1));
767                 } else {
768                         ret_val = get_lp_apm() / ((pre_pdf + 1) * (pdf + 1));
769                 }
770                 break;
771         default:
772                 diag_printf("%s(): This clock: %d not supported yet\n",
773                                         __FUNCTION__, clk);
774         }
775
776         return ret_val;
777 }
778
779 #ifdef L2CC_ENABLED
780 /*
781  * This command is added for some simple testing only. It turns on/off
782  * L2 cache regardless of L1 cache state. The side effect of this is
783  * when doing any flash operations such as "fis init", the L2
784  * will be turned back on along with L1 caches even though it is off
785  * by using this command.
786  */
787 RedBoot_cmd("L2",
788                         "L2 cache",
789                         "[ON | OFF]",
790                         do_L2_caches
791         );
792
793 void do_L2_caches(int argc, char *argv[])
794 {
795         u32 oldints;
796
797         if (argc == 2) {
798                 if (strcasecmp(argv[1], "on") == 0) {
799                         HAL_DISABLE_INTERRUPTS(oldints);
800                         HAL_ENABLE_L2();
801                         HAL_RESTORE_INTERRUPTS(oldints);
802                 } else if (strcasecmp(argv[1], "off") == 0) {
803                         HAL_DISABLE_INTERRUPTS(oldints);
804                         HAL_DCACHE_DISABLE_L1();
805                         HAL_CACHE_FLUSH_ALL();
806                         HAL_DISABLE_L2();
807                         HAL_DCACHE_ENABLE_L1();
808                         HAL_RESTORE_INTERRUPTS(oldints);
809                 } else {
810                         diag_printf("Invalid L2 cache mode: %s\n", argv[1]);
811                 }
812         } else {
813                 int L2cache_on;
814
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         u32 status, error;
843
844         if (action != POLL_FUSE_PRGD && action != POLL_FUSE_SNSD) {
845                 diag_printf("%s(%d) invalid operation\n", __FUNCTION__, action);
846                 return -1;
847         }
848
849         /* Poll busy bit till it is NOT set */
850         while ((readl(IIM_BASE_ADDR + IIM_STAT_OFF) & IIM_STAT_BUSY) != 0 ) {
851         }
852
853         /* Test for successful write */
854         status = readl(IIM_BASE_ADDR + IIM_STAT_OFF);
855         error = readl(IIM_BASE_ADDR + IIM_ERR_OFF);
856
857         if ((status & action) != 0 && (error & (action >> IIM_ERR_SHIFT)) == 0) {
858                 if (error) {
859                         diag_printf("Even though the operation seems successful...\n");
860                         diag_printf("There are some error(s) at addr=0x%08lx: 0x%08x\n",
861                                                 (IIM_BASE_ADDR + IIM_ERR_OFF), error);
862                 }
863                 return 0;
864         }
865         diag_printf("%s(%d) failed\n", __FUNCTION__, action);
866         diag_printf("status address=0x%08lx, value=0x%08x\n",
867                                 (IIM_BASE_ADDR + IIM_STAT_OFF), status);
868         diag_printf("There are some error(s) at addr=0x%08lx: 0x%08x\n",
869                                 (IIM_BASE_ADDR + IIM_ERR_OFF), error);
870         return -1;
871 }
872
873 unsigned int sense_fuse(int bank, int row, int bit)
874 {
875         int addr, addr_l, addr_h, reg_addr;
876
877         fuse_op_start();
878
879         addr = ((bank << 11) | (row << 3) | (bit & 0x7));
880         /* Set IIM Program Upper Address */
881         addr_h = (addr >> 8) & 0x000000FF;
882         /* Set IIM Program Lower Address */
883         addr_l = (addr & 0x000000FF);
884
885 #ifdef IIM_FUSE_DEBUG
886         diag_printf("%s: addr_h=0x%02x, addr_l=0x%02x\n",
887                                 __FUNCTION__, addr_h, addr_l);
888 #endif
889         writel(addr_h, IIM_BASE_ADDR + IIM_UA_OFF);
890         writel(addr_l, IIM_BASE_ADDR + IIM_LA_OFF);
891         /* Start sensing */
892         writel(0x8, IIM_BASE_ADDR + IIM_FCTL_OFF);
893         if (poll_fuse_op_done(POLL_FUSE_SNSD) != 0) {
894                 diag_printf("%s(bank: %d, row: %d, bit: %d failed\n",
895                                         __FUNCTION__, bank, row, bit);
896         }
897         reg_addr = IIM_BASE_ADDR + IIM_SDAT_OFF;
898         return readl(reg_addr);
899 }
900
901 void do_fuse_read(int argc, char *argv[])
902 {
903         unsigned long bank, row;
904         unsigned long fuse_val;
905
906         if (argc == 1) {
907                 diag_printf("Usage: fuse_read <bank> <row>\n");
908                 return;
909         } else if (argc == 3) {
910                 if (!parse_num(argv[1], &bank, &argv[1], " ")) {
911                         diag_printf("Error: Invalid parameter\n");
912                         return;
913                 }
914                 if (!parse_num(argv[2], &row, &argv[2], " ")) {
915                         diag_printf("Error: Invalid parameter\n");
916                         return;
917                 }
918
919                 diag_printf("Read fuse at bank:%ld row:%ld\n", bank, row);
920                 fuse_val = sense_fuse(bank, row, 0);
921                 diag_printf("fuses at (bank:%ld, row:%ld) = 0x%02lx\n", bank, row, fuse_val);
922         } else {
923                 diag_printf("Passing in wrong arguments: %d\n", argc);
924                 diag_printf("Usage: 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 fuse %d %d bit %d addr_h=0x%02x, addr_l=0x%02x\n",
947                                 bank, row, bit, addr_h, addr_l);
948 #endif
949
950         writel(addr_h, IIM_BASE_ADDR + IIM_UA_OFF);
951         writel(addr_l, IIM_BASE_ADDR + IIM_LA_OFF);
952         /* Start Programming */
953         writel(0x71, IIM_BASE_ADDR + IIM_FCTL_OFF);
954         if (poll_fuse_op_done(POLL_FUSE_PRGD) == 0) {
955                 ret = 0;
956         }
957
958         /* Enable IIM Program Protect */
959         writel(0x0, IIM_BASE_ADDR + IIM_PREG_P_OFF);
960         return ret;
961 }
962
963 /*
964  * This command is added for burning IIM fuses
965  */
966 RedBoot_cmd("fuse_read",
967                         "read some fuses",
968                         "<bank> <row>",
969                         do_fuse_read
970         );
971
972 RedBoot_cmd("fuse_blow",
973                         "blow some fuses",
974                         "<bank> <row> <value>",
975                         do_fuse_blow
976         );
977
978 void quick_itoa(u32 num, char *a)
979 {
980         int i, j, k;
981         for (i = 0; i <= 7; i++) {
982                 j = (num >> (4 * i)) & 0xF;
983                 k = (j < 10) ? '0' : ('a' - 0xa);
984                 a[i] = j + k;
985         }
986 }
987
988 // slen - streng length, e.g.: 23 -> slen=2; abcd -> slen=4
989 // only convert hex value as string input. so "12" is 0x12.
990 u32 quick_atoi(char *a, u32 slen)
991 {
992         u32 i, num = 0, digit;
993
994         for (i = 0; i < slen; i++) {
995                 if (a[i] >= '0' && a[i] <= '9') {
996                         digit = a[i] - '0';
997                 } else if (a[i] >= 'a' && a[i] <= 'f') {
998                         digit = a[i] - 'a' + 10;
999                 } else if (a[i] >= 'A' && a[i] <= 'F') {
1000                         digit = a[i] - 'A' + 10;
1001                 } else {
1002                         diag_printf("ERROR: %c\n", a[i]);
1003                         return -1;
1004                 }
1005                 num = (num * 16) + digit;
1006         }
1007         return num;
1008 }
1009
1010 void fuse_blow_row(int bank, int row, int value)
1011 {
1012         unsigned int reg, i;
1013
1014         FUSE_PROG_START();
1015
1016         // enable fuse blown
1017         reg = readl(CCM_BASE_ADDR + 0x64);
1018         reg |= 0x10;
1019         writel(reg, CCM_BASE_ADDR + 0x64);
1020
1021         for (i = 0; i < 8; i++) {
1022                 if (((value >> i) & 0x1) == 0) {
1023                         continue;
1024                 }
1025                 if (fuse_blow(bank, row, i) != 0) {
1026                         diag_printf("fuse_blow(bank: %d, row: %d, bit: %d failed\n",
1027                                                 bank, row, i);
1028                 }
1029         }
1030         reg &= ~0x10;
1031         writel(reg, CCM_BASE_ADDR + 0x64);
1032
1033         FUSE_PROG_DONE();
1034 }
1035
1036 void do_fuse_blow(int argc, char *argv[])
1037 {
1038         unsigned long bank, row, value, i;
1039         unsigned int fuse_val;
1040         char *s;
1041         char val[3];
1042
1043         if (argc == 1) {
1044                 diag_printf("It is too dangeous for you to use this command.\n");
1045                 return;
1046         }
1047
1048         if (argc == 3) {
1049                 if (strcasecmp(argv[1], "scc") == 0) {
1050                         // fuse_blow scc C3D153EDFD2EA9982226EF5047D3B9A0B9C7138EA87C028401D28C2C2C0B9AA2
1051                         diag_printf("Ready to burn SCC fuses\n");
1052                         s=argv[2];
1053                         for (i = 0; ;i++) {
1054                                 memcpy(val, s, 2);
1055                                 val[2]='\0';
1056                                 value = quick_atoi(val, 2);
1057                                 //    diag_printf("fuse_blow_row(2, %d, value=0x%02x)\n", i, value);
1058                                 fuse_blow_row(2, i, value);
1059
1060                                 if ((++s)[0] == '\0') {
1061                                         diag_printf("ERROR: Odd string input\n");
1062                                         break;
1063                                 }
1064                                 if ((++s)[0] == '\0') {
1065                                         diag_printf("Successful\n");
1066                                         break;
1067                                 }
1068                         }
1069                 } else if (strcasecmp(argv[1], "srk") == 0) {
1070                         // fuse_blow srk 418bccd09b53bee1ab59e2662b3c7877bc0094caee201052add49be8780dff95
1071                         diag_printf("Ready to burn SRK key fuses\n");
1072                         s=argv[2];
1073                         for (i = 0; ;i++) {
1074                                 memcpy(val, s, 2);
1075                                 val[2]='\0';
1076                                 value = quick_atoi(val, 2);
1077                                 if (i == 0) {
1078                                         fuse_blow_row(1, 1, value); // 0x41 goes to SRK_HASH[255:248], bank 1, row 1
1079                                 } else
1080                                         fuse_blow_row(3, i, value);  // 0x8b in SRK_HASH[247:240] bank 3, row 1
1081                                                                                                  // 0xcc in SRK_HASH[239:232] bank 3, row 2
1082                                                                                                  // ...
1083                                 if ((++s)[0] == '\0') {
1084                                         diag_printf("ERROR: Odd string input\n");
1085                                         break;
1086                                 }
1087                                 if ((++s)[0] == '\0') {
1088                                         diag_printf("Successful\n");
1089                                         break;
1090                                 }
1091                         }
1092                 } else
1093                         diag_printf("This command is not supported\n");
1094
1095                 return;
1096         } else if (argc == 4) {
1097                 if (!parse_num(argv[1], &bank, &argv[1], " ")) {
1098                         diag_printf("Error: Invalid parameter\n");
1099                         return;
1100                 }
1101                 if (!parse_num(argv[2], &row, &argv[2], " ")) {
1102                         diag_printf("Error: Invalid parameter\n");
1103                         return;
1104                 }
1105                 if (!parse_num(argv[3], &value, &argv[3], " ")) {
1106                         diag_printf("Error: Invalid parameter\n");
1107                         return;
1108                 }
1109
1110                 diag_printf("Blowing fuse at bank:%ld row:%ld value:%ld\n",
1111                                         bank, row, value);
1112                 fuse_blow_row(bank, row, value);
1113                 fuse_val = sense_fuse(bank, row, 0);
1114                 diag_printf("fuses at (bank:%ld, row:%ld) = 0x%02x\n", bank, row, fuse_val);
1115
1116         } else {
1117                 diag_printf("Passing in wrong arguments: %d\n", argc);
1118         }
1119 }
1120
1121 /* precondition: m>0 and n>0.  Let g=gcd(m,n). */
1122 static int gcd(int m, int n)
1123 {
1124         while (m > 0) {
1125                 if (n > m) {
1126                         /* swap */
1127                         m ^= n;
1128                         n ^= m;
1129                         m ^= n;
1130                 }
1131                 m -= n;
1132         }
1133         return n;
1134 }
1135
1136 int read_mac_addr_from_fuse(unsigned char* data)
1137 {
1138         data[0] = sense_fuse(1, 9, 0) ;
1139         data[1] = sense_fuse(1, 10, 0) ;
1140         data[2] = sense_fuse(1, 11, 0) ;
1141         data[3] = sense_fuse(1, 12, 0) ;
1142         data[4] = sense_fuse(1, 13, 0) ;
1143         data[5] = sense_fuse(1, 14, 0) ;
1144
1145         if ((data[0] == 0) && (data[1] == 0) && (data[2] == 0) &&
1146                 (data[3] == 0) && (data[4] == 0) && (data[5] == 0)) {
1147                 return 0;
1148         }
1149
1150         return 1;
1151 }
1152
1153 #if 0
1154 void imx_power_mode(int mode)
1155 {
1156         volatile unsigned int val;
1157         switch (mode) {
1158         case 2:
1159                 writel(0x0000030f, GPC_PGR);
1160                 writel(0x1, SRPGCR_EMI);
1161                 writel(0x1, SRPGCR_ARM);
1162                 writel(0x1, PGC_PGCR_VPU);
1163                 writel(0x1, PGC_PGCR_IPU);
1164
1165
1166         case 1:
1167                 // stop mode - from validation code
1168                 // Set DSM_INT_HOLDOFF bit in TZIC
1169                 // If the TZIC didn't write the bit then there was interrupt pending
1170                 // It will be serviced while we're in the loop
1171                 // So we write to this bit again
1172                 while (readl(INTC_BASE_ADDR + 0x14) == 0) {
1173                         writel(1, INTC_BASE_ADDR + 0x14);
1174                         // Wait few cycles
1175                         __asm("nop");
1176                         __asm("nop");
1177                         __asm("nop");
1178                         __asm("nop");
1179                         __asm("nop");
1180                         __asm("nop");
1181                         __asm("nop");
1182                 }
1183                 diag_printf("Entering stop mode\n");
1184                 val = readl(CCM_BASE_ADDR + 0x74);
1185                 val = (val & 0xfffffffc) | 0x2; // set STOP mode
1186                 writel(val, CCM_BASE_ADDR + 0x74);
1187                 val = readl(PLATFORM_LPC_REG);
1188                 writel(val | (1 << 16), PLATFORM_LPC_REG);// ENABLE DSM in ELBOW submodule of ARM platform
1189                 writel(val | (1 << 17), PLATFORM_LPC_REG);// ENABLE DSM in ELBOW submodule of ARM platform
1190                 break;
1191         }
1192
1193         hal_delay_us(50);
1194
1195         asm("mov r1, #0");
1196         asm("mcr p15, 0, r1, c7, c0, 4");
1197 }
1198
1199 void do_power_mode(int argc, char *argv[])
1200 {
1201         unsigned long mode;
1202
1203         if (argc == 1) {
1204                 diag_printf("Usage: power_mode <mode>\n");
1205                 return;
1206         } else if (argc == 2) {
1207                 if (!parse_num(argv[1], &mode, &argv[1], " ")) {
1208                         diag_printf("Error: Invalid parameter\n");
1209                         return;
1210                 }
1211                 diag_printf("Entering power mode: %lu\n", mode);
1212                 imx_power_mode(mode);
1213
1214         } else {
1215                 diag_printf("Passing in wrong arguments: %d\n", argc);
1216                 diag_printf("Usage: power_mode <mode>\n");
1217         }
1218 }
1219
1220 /*
1221  * This command is added for burning IIM fuses
1222  */
1223 RedBoot_cmd("power_mode",
1224                         "Enter various power modes:",
1225                         "\n"
1226                         "           <0> - WAIT\n"
1227                         "           <1> - SRPG\n"
1228                         "           <2> - STOP\n"
1229                         "           <3> - STOP with Power-Gating\n"
1230                         "           -- need reset after issuing the command",
1231                         do_power_mode
1232         );
1233 #endif
1234
1235 /* Super Root key moduli */
1236 static const UINT8 hab_super_root_moduli[] = {
1237         /* modulus data */
1238         0xb9, 0x84, 0xc8, 0x8a, 0xd3, 0x7e, 0xcc, 0xc0, 0xe7, 0x3e, 0x11, 0x53,
1239         0x6b, 0x5e, 0xea, 0xf4, 0xd9, 0xac, 0x5a, 0x63, 0x8a, 0x79, 0x96, 0x83,
1240         0xb1, 0x39, 0xb2, 0x6f, 0x9c, 0x54, 0x87, 0xf4, 0x3b, 0x9e, 0xd8, 0x0f,
1241         0x89, 0xf5, 0x01, 0x53, 0xb8, 0xe2, 0xcc, 0x75, 0x0d, 0xe1, 0x13, 0xfa,
1242         0xa7, 0xb9, 0x1e, 0xff, 0x6a, 0x05, 0xdb, 0x58, 0x10, 0xbf, 0x2b, 0xf4,
1243         0xe7, 0x0a, 0x63, 0x82, 0x2c, 0xa3, 0xb5, 0x0a, 0x72, 0x1c, 0xdc, 0x29,
1244         0xc1, 0x81, 0xb5, 0x9a, 0xf0, 0x25, 0x7d, 0xd6, 0xee, 0x01, 0x64, 0xc7,
1245         0x07, 0x2d, 0xcb, 0x31, 0x4c, 0x8d, 0x82, 0xf6, 0x44, 0x95, 0x4a, 0xbc,
1246         0xae, 0xe8, 0x2a, 0x89, 0xd4, 0xf2, 0x66, 0x72, 0x2b, 0x09, 0x4e, 0x56,
1247         0xe9, 0xbf, 0x5e, 0x38, 0x5c, 0xd5, 0x7e, 0x15, 0x55, 0x86, 0x0f, 0x19,
1248         0xf6, 0x00, 0xee, 0xa1, 0x92, 0x78, 0xef, 0x93, 0xcb, 0xfa, 0xb4, 0x98,
1249         0x19, 0xef, 0x10, 0x70, 0xde, 0x36, 0x1c, 0x12, 0x2e, 0xd2, 0x09, 0xc7,
1250         0x7b, 0xd1, 0xaa, 0xd3, 0x46, 0x65, 0xa1, 0x5b, 0xee, 0xa5, 0x96, 0x97,
1251         0x98, 0x3e, 0xfc, 0xf8, 0x74, 0x22, 0x51, 0xe7, 0xf1, 0x2f, 0x30, 0x79,
1252         0x13, 0xe5, 0x42, 0xc6, 0x7c, 0x18, 0x76, 0xd3, 0x7f, 0x5a, 0x13, 0xde,
1253         0x2f, 0x51, 0x07, 0xfa, 0x93, 0xfe, 0x10, 0x8a, 0x0c, 0x18, 0x60, 0x3c,
1254         0xff, 0x6a, 0x9b, 0xe7, 0x10, 0x2d, 0x71, 0xd2, 0x34, 0xc0, 0xdf, 0xbe,
1255         0x17, 0x4e, 0x75, 0x40, 0x83, 0xaa, 0x90, 0xd1, 0xed, 0xbd, 0xbf, 0xac,
1256         0x9a, 0x30, 0xbd, 0x69, 0x4d, 0xd8, 0x00, 0x63, 0x92, 0x69, 0x98, 0xf8,
1257         0x89, 0xdc, 0x7b, 0xe3, 0x66, 0x7e, 0xdd, 0xfa, 0x8c, 0x74, 0xe2, 0xb1,
1258         0xeb, 0x94, 0xf7, 0xab, 0x0e, 0x92, 0x06, 0xab, 0x60, 0xe5, 0x00, 0x43,
1259         0xb2, 0x5e, 0x6e, 0xeb
1260 };
1261
1262 /* Super Root key */
1263 const hab_rsa_public_key hab_super_root_key[] = {
1264         {
1265                 {
1266                         /* RSA public exponent, right-padded */
1267                         0x01, 0x00, 0x01, 0x00,
1268                 },
1269                 /* pointer to modulus data */
1270                 hab_super_root_moduli,
1271                 /* Exponent size in bytes */
1272                 0x03,
1273                 /* Modulus size in bytes */
1274                 0x100,
1275                 /* Key data valid */
1276                 TRUE
1277         }
1278 };