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