]> git.kernelconcepts.de Git - karo-tx-redboot.git/blob - packages/hal/arm/mx51/var/v2_0/src/cmds.c
RedBoot STK5 Release 2010-03-04
[karo-tx-redboot.git] / packages / hal / arm / mx51 / var / v2_0 / src / cmds.c
1 //==========================================================================
2 //
3 //      cmds.c
4 //
5 //      SoC [platform] specific RedBoot commands
6 //
7 //==========================================================================
8 //####ECOSGPLCOPYRIGHTBEGIN####
9 // -------------------------------------------
10 // This file is part of eCos, the Embedded Configurable Operating System.
11 // Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
12 //
13 // eCos is free software; you can redistribute it and/or modify it under
14 // the terms of the GNU General Public License as published by the Free
15 // Software Foundation; either version 2 or (at your option) any later version.
16 //
17 // eCos is distributed in the hope that it will be useful, but WITHOUT ANY
18 // WARRANTY; without even the implied warranty of MERCHANTABILITY or
19 // FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
20 // for more details.
21 //
22 // You should have received a copy of the GNU General Public License along
23 // with eCos; if not, write to the Free Software Foundation, Inc.,
24 // 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
25 //
26 // As a special exception, if other files instantiate templates or use macros
27 // or inline functions from this file, or you compile this file and link it
28 // with other works to produce a work based on this file, this file does not
29 // by itself cause the resulting work to be covered by the GNU General Public
30 // License. However the source code for this file must still be made available
31 // in accordance with section (3) of the GNU General Public License.
32 //
33 // This exception does not invalidate any other reasons why a work based on
34 // this file might be covered by the GNU General Public License.
35 //
36 // Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
37 // at http://sources.redhat.com/ecos/ecos-license/
38 // -------------------------------------------
39 //####ECOSGPLCOPYRIGHTEND####
40 //==========================================================================
41 #include <redboot.h>
42 #include <cyg/hal/hal_intr.h>
43 #include <cyg/hal/plf_mmap.h>
44 #include <cyg/hal/hal_soc.h>             // Hardware definitions
45 #include <cyg/hal/hal_cache.h>
46
47 #include "hab_super_root.h"
48
49 //#define IIM_FUSE_DEBUG
50 //#define CMD_CLOCK_DEBUG
51 #ifdef CMD_CLOCK_DEBUG
52 #define dbg(fmt...)                                                             \
53   CYG_MACRO_START                                                               \
54   diag_printf(fmt);                                                             \
55   CYG_MACRO_END
56 #else
57 #define dbg(fmt...)             CYG_EMPTY_STATEMENT
58 #endif
59
60 int gcd(int m, int n);
61 extern void increase_core_voltage(bool i);
62
63 typedef unsigned long long      u64;
64 typedef unsigned int            u32;
65 typedef unsigned short          u16;
66 typedef unsigned char           u8;
67
68 #define SZ_DEC_1M               1000000
69 #define PLL_PD_MAX              16              //actual pd+1
70 #define PLL_MFI_MAX             15
71 #define PLL_MFI_MIN             5
72 #define ARM_DIV_MAX             8
73 #define IPG_DIV_MAX             4
74 #define AHB_DIV_MAX             8
75 #define EMI_DIV_MAX             8
76 #define NFC_DIV_MAX             8
77
78 #define REF_IN_CLK_NUM  4
79 struct fixed_pll_mfd {
80         u32 ref_clk_hz;
81         u32 mfd;
82 };
83
84 const struct fixed_pll_mfd fixed_mfd[REF_IN_CLK_NUM] = {
85         { 0,                                      0, },    // reserved
86         { 0,                                      0, },    // reserved
87         { FREQ_24MHZ,           24 * 16, },        // internal osc
88         { FREQ_32768HZ,            1024, },        // FPM
89 };
90
91 struct pll_param {
92         u32 pd;
93         u32 mfi;
94         u32 mfn;
95         u32 mfd;
96 };
97
98 #define PLL_FREQ_MAX(_ref_clk_)    (4 * _ref_clk_ * PLL_MFI_MAX)
99 #define PLL_FREQ_MIN(_ref_clk_)    ((2 * _ref_clk_ * (PLL_MFI_MIN - 1)) / PLL_PD_MAX)
100 #define MAX_DDR_CLK             220000000
101 #define AHB_CLK_MAX             133333333
102 #define IPG_CLK_MAX             (AHB_CLK_MAX / 2)
103 #define NFC_CLK_MAX             25000000
104 // IPU-HSP clock is independent of the HCLK and can go up to 177MHz but requires
105 // higher voltage support. For simplicity, limit it to 133MHz
106 #define HSP_CLK_MAX             133333333
107
108 #define ERR_WRONG_CLK   (-1)
109 #define ERR_NO_MFI              (-2)
110 #define ERR_NO_MFN              (-3)
111 #define ERR_NO_PD               (-4)
112 #define ERR_NO_PRESC    (-5)
113 #define ERR_NO_AHB_DIV  (-6)
114
115 u32 pll_clock(enum plls pll);
116 u32 get_main_clock(enum main_clocks clk);
117 u32 get_peri_clock(enum peri_clocks clk);
118
119 static volatile u32 *pll_base[] =
120 {
121         REG32_PTR(PLL1_BASE_ADDR),
122         REG32_PTR(PLL2_BASE_ADDR),
123         REG32_PTR(PLL3_BASE_ADDR),
124 };
125
126 #define NOT_ON_VAL  0xDEADBEEF
127
128 static void clock_setup(int argc, char *argv[]);
129
130 RedBoot_cmd("clock",
131                         "Setup/Display clock\nSyntax:",
132                         "[<core clock in MHz> :<DDR clock in MHz>]\n\n"
133                         "   Examples:\n"
134                         "   [clock]         -> Show various clocks\n"
135                         "   [clock 665]     -> Core=665\n"
136                         "   [clock 800:133] -> Core=800 DDR=133\n"
137                         "   [clock :166]    -> Core=no change DDR=166\n",
138                         clock_setup
139         );
140
141 /*!
142  * This is to calculate various parameters based on reference clock and
143  * targeted clock based on the equation:
144  *      t_clk = 2*ref_freq*(mfi + mfn/(mfd+1))/(pd+1)
145  * This calculation is based on a fixed MFD value for simplicity.
146  *
147  * @param ref       reference clock freq in Hz
148  * @param target    targeted clock in Hz
149  * @param p_pd      calculated pd value (pd value from register + 1) upon return
150  * @param p_mfi     calculated actual mfi value upon return
151  * @param p_mfn     calculated actual mfn value upon return
152  * @param p_mfd     fixed mfd value (mfd value from register + 1) upon return
153  *
154  * @return          0 if successful; non-zero otherwise.
155  */
156 int calc_pll_params(u32 ref, u32 target, struct pll_param *pll)
157 {
158         u64 pd, mfi = 1, mfn, mfd, n_target = target, n_ref = ref, i;
159
160         // make sure targeted freq is in the valid range. Otherwise the
161         // following calculation might be wrong!!!
162         if (n_target < PLL_FREQ_MIN(ref) || n_target > PLL_FREQ_MAX(ref))
163                 return ERR_WRONG_CLK;
164         for (i = 0; ; i++) {
165                 if (i == REF_IN_CLK_NUM)
166                         return ERR_WRONG_CLK;
167                 if (fixed_mfd[i].ref_clk_hz == ref) {
168                         mfd = fixed_mfd[i].mfd;
169                         break;
170                 }
171         }
172
173         // Use n_target and n_ref to avoid overflow
174         for (pd = 1; pd <= PLL_PD_MAX; pd++) {
175                 mfi = (n_target * pd) / (4 * n_ref);
176                 if (mfi > PLL_MFI_MAX) {
177                         return ERR_NO_MFI;
178                 } else if (mfi < 5) {
179                         continue;
180                 }
181                 break;
182         }
183         // Now got pd and mfi already
184         mfn = (((n_target * pd) / 4 - n_ref * mfi) * mfd) / n_ref;
185
186         dbg("%d: ref=%d, target=%d, pd=%d, mfi=%d,mfn=%d, mfd=%d\n",
187                 __LINE__, ref, (u32)n_target, (u32)pd, (u32)mfi, (u32)mfn, (u32)mfd);
188
189         i = 1;
190         if (mfn != 0)
191                 i = gcd(mfd, mfn);
192         pll->pd = (u32)pd;
193         pll->mfi = (u32)mfi;
194         pll->mfn = (u32)(mfn / i);
195         pll->mfd = (u32)(mfd / i);
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 stoped. 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                         increase_core_voltage(true);
332                 } else {
333                         div_core = 2;
334                         increase_core_voltage(false);
335                 }
336
337                 // adjust pll settings
338                 writel(((pll_param.pd - 1) << 0) | (pll_param.mfi << 4),
339                         PLL1_BASE_ADDR + PLL_DP_OP);
340                 writel(pll_param.mfn, PLL1_BASE_ADDR + PLL_DP_MFN);
341                 writel(pll_param.mfd - 1, PLL1_BASE_ADDR + PLL_DP_MFD);
342                 writel(((pll_param.pd - 1) << 0) | (pll_param.mfi << 4),
343                         PLL1_BASE_ADDR + PLL_DP_HFS_OP);
344                 writel(pll_param.mfn, PLL1_BASE_ADDR + PLL_DP_HFS_MFN);
345                 writel(pll_param.mfd - 1, PLL1_BASE_ADDR + PLL_DP_HFS_MFD);
346
347                 icgc &= ~0x77;
348                 icgc |= div_core << 4;
349                 icgc |= div_per;
350                 /* Set the platform clock dividers */
351                 writel(icgc, PLATFORM_BASE_ADDR + PLATFORM_ICGC);
352                 /* Switch ARM back to PLL1 */
353                 writel((ccsr & ~0x4), CCM_BASE_ADDR + CLKCTL_CCSR);
354                 /* Applies for TO 2 only */
355                 if (((cbcdr >> 30) & 0x1) == 0x1) {
356                         /* Disable IPU and HSC dividers */
357                         writel(0x60000, CCM_BASE_ADDR + CLKCTL_CCDR);
358                         /* Switch DDR back to PLL1 */
359                         writel(cbcdr | 0x40000000, CCM_BASE_ADDR + CLKCTL_CBCDR);
360                         while (readl(CCM_BASE_ADDR + CLKCTL_CDHIPR) != 0);
361                         writel(0x0, CCM_BASE_ADDR + CLKCTL_CCDR);
362                         if (emi_clk == 0) {
363                                 /* Keep EMI clock to the max if not specified */
364                                 emi_clk = 200000000;
365                         }
366                 }
367         }
368
369         if (emi_clk != 0) {
370                 /* Applies for TO 2 only */
371                 if (((cbcdr >> 30) & 0x1) == 0x1) {
372                         clk_src = pll_clock(PLL1);
373                         shift = 27;
374                 } else {
375                         clk_src = get_periph_clk();
376                         /* Find DDR clock input */
377                         clk_sel = (cbcmr >> 10) & 0x3;
378                         if (clk_sel == 0) {
379                                 shift = 16;
380                         } else if (clk_sel == 1) {
381                                 shift = 19;
382                         } else if (clk_sel == 2) {
383                                 shift = 22;
384                         } else if (clk_sel == 3) {
385                                 shift = 10;
386                         }
387                 }
388                 if ((clk_src % emi_clk) == 0)
389                         div = clk_src / emi_clk;
390                 else
391                         div = (clk_src / emi_clk) + 1;
392                 if (div > 8)
393                         div = 8;
394
395                 cbcdr &= ~(0x7 << shift);
396                 cbcdr |= (div - 1) << shift;
397                 dbg("%s@%d: \n", __FUNCTION__, __LINE__);
398
399                 /* Disable IPU and HSC dividers */
400                 writel(0x60000, CCM_BASE_ADDR + CLKCTL_CCDR);
401                 writel(cbcdr, CCM_BASE_ADDR + CLKCTL_CBCDR);
402                 while (readl(CCM_BASE_ADDR + CLKCTL_CDHIPR) != 0);
403                 writel(0x0, CCM_BASE_ADDR + CLKCTL_CCDR);
404         }
405         return 0;
406 }
407
408 static void clock_setup(int argc,char *argv[])
409 {
410         u32 i, core_clk, ddr_clk, data[3];
411         unsigned long temp;
412         int ret;
413
414         if (argc == 1)
415                 goto print_clock;
416
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", (MAX_DDR_CLK / SZ_DEC_1M));
439                         ddr_clk = MAX_DDR_CLK;
440                 }
441         }
442
443 #if 1
444         // stop the serial to be ready to adjust the clock
445         hal_delay_us(100000);
446         cyg_hal_plf_serial_stop();
447         // adjust the clock
448 #endif
449         ret = configure_clock(PLL_REF_CLK, core_clk, ddr_clk);
450         // restart the serial driver
451         cyg_hal_plf_serial_init();
452         hal_delay_us(100000);
453
454         if (ret != 0) {
455                 diag_printf("Failed to setup clock: %d\n", ret);
456                 return;
457         }
458         diag_printf("\n<<<New clock setting>>>\n");
459
460         // Now printing clocks
461 print_clock:
462
463         diag_printf("\nPLL1\t\tPLL2\t\tPLL3\n");
464         diag_printf("========================================\n");
465         diag_printf("%-16d%-16d%-16d\n\n", pll_clock(PLL1), pll_clock(PLL2),
466                                 pll_clock(PLL3));
467         diag_printf("CPU\t\tAHB\t\tIPG\t\tEMI_CLK\n");
468         diag_printf("========================================================\n");
469         diag_printf("%-16d%-16d%-16d%-16d\n\n",
470                                 get_main_clock(CPU_CLK),
471                                 get_main_clock(AHB_CLK),
472                                 get_main_clock(IPG_CLK),
473                                 get_main_clock(DDR_CLK));
474
475         diag_printf("NFC\t\tUSB\t\tIPG_PER_CLK\n");
476         diag_printf("========================================\n");
477         diag_printf("%-16d%-16d%-16d\n\n",
478                                 get_main_clock(NFC_CLK),
479                                 get_main_clock(USB_CLK),
480                                 get_main_clock(IPG_PER_CLK));
481
482         diag_printf("UART1-3\t\tSSI1\t\tSSI2\t\tSPI\n");
483         diag_printf("===========================================");
484         diag_printf("=============\n");
485
486         diag_printf("%-16d%-16d%-16d%-16d\n\n",
487                                 get_peri_clock(UART1_BAUD),
488                                 get_peri_clock(SSI1_BAUD),
489                                 get_peri_clock(SSI2_BAUD),
490                                 get_peri_clock(SPI1_CLK));
491
492 #if 0
493         diag_printf("IPG_PERCLK as baud clock for: UART1-5, I2C, OWIRE, SDHC");
494         if (((readl(EPIT1_BASE_ADDR) >> 24) & 0x3) == 0x2) {
495                 diag_printf(", EPIT");
496         }
497         if (((readl(GPT1_BASE_ADDR) >> 6) & 0x7) == 0x2) {
498                 diag_printf("GPT,");
499         }
500 #endif
501         diag_printf("\n");
502
503 }
504
505 /*!
506  * This function returns the PLL output value in Hz based on pll.
507  */
508 u32 pll_clock(enum plls pll)
509 {
510         u64 ref_clk;
511         u32 mfi, mfn, mfd, pdf, pll_out, sign;
512         u32 dp_ctrl, dp_op, dp_mfd, dp_mfn;
513         int clk_sel;
514         int dbl;
515
516         dp_ctrl = pll_base[pll][PLL_DP_CTL >> 2];
517         clk_sel = MXC_GET_FIELD(dp_ctrl, 2, 8);
518         ref_clk = fixed_mfd[clk_sel].ref_clk_hz;
519
520         dbg("clk_sel=%d\n", clk_sel);
521
522         if ((pll_base[pll][PLL_DP_CTL >> 2] & 0x80) == 0) {
523                 dp_op = pll_base[pll][PLL_DP_OP >> 2];
524                 dp_mfd = pll_base[pll][PLL_DP_MFD >> 2];
525                 dp_mfn = pll_base[pll][PLL_DP_MFN >> 2];
526         } else {
527                 dp_op = pll_base[pll][PLL_DP_HFS_OP >> 2];
528                 dp_mfd = pll_base[pll][PLL_DP_HFS_MFD >> 2];
529                 dp_mfn = pll_base[pll][PLL_DP_HFS_MFN >> 2];
530         }
531         pdf = dp_op & 0xF;
532         mfi = (dp_op >> 4) & 0xF;
533         mfi = (mfi <= 5) ? 5: mfi;
534         mfd = dp_mfd & 0x07FFFFFF;
535         mfn = dp_mfn & 0x07FFFFFF;
536
537         sign = (mfn < 0x4000000) ? 1 : -1;
538         mfn = (mfn < 0x4000000) ? mfn : (0x8000000 - mfn);
539
540         dbl = 2 * (((dp_ctrl >> 12) & 0x1) + 1);
541
542         dbg("%s: ref=%llu.%03lluMHz, dbl=%d, pd=%d, mfi=%d, mfn=%s%d, mfd=%d\n",
543                 __FUNCTION__, ref_clk / 1000000, ref_clk / 1000 % 1000,
544                 dbl, pdf, mfi, sign ? "-" : "", mfn, mfd);
545
546         pll_out = (dbl * ref_clk * mfi + ((dbl * ref_clk * sign * mfn) / (mfd + 1))) /
547                 (pdf + 1);
548
549         return pll_out;
550 }
551
552 /*!
553  * This function returns the emi_core_clk_root clock.
554  */
555 u32 get_emi_core_clk(void)
556 {
557         u32 cbcdr = readl(CCM_BASE_ADDR + CLKCTL_CBCDR);
558         u32 clk_sel, max_pdf, peri_clk, ahb_clk;
559         u32 ret_val;
560
561         max_pdf = (cbcdr >> 10) & 0x7;
562         peri_clk = get_periph_clk();
563         ahb_clk = peri_clk / (max_pdf + 1);
564
565         clk_sel = (cbcdr >> 26) & 1;
566         if (clk_sel == 0) {
567                 ret_val = peri_clk;
568         } else {
569                 ret_val = ahb_clk ;
570         }
571         dbg("%s: CBCDR[%08lx]=%08x freq=%u.%03uMHz\n", __FUNCTION__,
572                 CCM_BASE_ADDR + CLKCTL_CBCDR, cbcdr, ret_val / 1000000, ret_val / 1000 % 1000);
573         return ret_val;
574 }
575
576 /*!
577  * This function returns the main clock value in Hz.
578  */
579 u32 get_main_clock(enum main_clocks clk)
580 {
581         u32 pdf, max_pdf, ipg_pdf, nfc_pdf, clk_sel;
582         u32 pll, ret_val;
583         u32 cacrr = readl(CCM_BASE_ADDR + CLKCTL_CACRR);
584         u32 cbcdr = readl(CCM_BASE_ADDR + CLKCTL_CBCDR);
585         u32 cbcmr = readl(CCM_BASE_ADDR + CLKCTL_CBCMR);
586         u32 cscmr1 = readl(CCM_BASE_ADDR + CLKCTL_CSCMR1);
587         u32 cscdr1 = readl(CCM_BASE_ADDR + CLKCTL_CSCDR1);
588
589         dbg("%s: \n", __FUNCTION__);
590         switch (clk) {
591         case CPU_CLK:
592                 pdf = cacrr & 0x7;
593                 pll = pll_clock(PLL1);
594                 ret_val = pll / (pdf + 1);
595                 break;
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         case IPG_CLK:
602                 max_pdf = (cbcdr >> 10) & 0x7;
603                 ipg_pdf = (cbcdr >> 8) & 0x3;
604                 pll = get_periph_clk();
605                 ret_val = pll / ((max_pdf + 1) * (ipg_pdf + 1));
606                 break;
607         case IPG_PER_CLK:
608                 clk_sel = cbcmr & 1;
609                 if (clk_sel == 0) {
610                         clk_sel = (cbcmr >> 1) & 1;
611                         pdf = (((cbcdr >> 6) & 3) + 1) * (((cbcdr >> 3) & 7) + 1) * ((cbcdr & 7) + 1);
612                         if (clk_sel == 0) {
613                                 ret_val = get_periph_clk() / pdf;
614                         } else {
615                                 ret_val = get_lp_apm();
616                         }
617                 } else {
618                         /* Same as IPG_CLK */
619                         max_pdf = (cbcdr >> 10) & 0x7;
620                         ipg_pdf = (cbcdr >> 8) & 0x3;
621                         pll = get_periph_clk();
622                         ret_val = pll / ((max_pdf + 1) * (ipg_pdf + 1));
623                 }
624                 break;
625         case DDR_CLK:
626                 if (cbcdr & (1 << 30)) {
627                         pll = pll_clock(PLL1);
628                         pdf = (cbcdr >> 27) & 0x7;
629                 } else {
630                         clk_sel = (cbcmr >> 10) & 3;
631                         pll = get_periph_clk();
632                         if (clk_sel == 0) {
633                                 /* AXI A */
634                                 pdf = (cbcdr >> 16) & 0x7;
635                         } else if (clk_sel == 1) {
636                                 /* AXI B */
637                                 pdf = (cbcdr >> 19) & 0x7;
638                         } else if (clk_sel == 2) {
639                                 /* EMI SLOW CLOCK ROOT */
640                                 pll = get_emi_core_clk();
641                                 pdf = (cbcdr >> 22) & 0x7;
642                         } else if (clk_sel == 3) {
643                                 /* AHB CLOCK */
644                                 pdf = (cbcdr >> 10) & 0x7;
645                         }
646                 }
647
648                 ret_val = pll / (pdf + 1);
649                 break;
650         case NFC_CLK:
651                 pdf = (cbcdr >> 22) & 0x7;
652                 nfc_pdf = (cbcdr >> 13) & 0x7;
653                 pll = get_emi_core_clk();
654                 ret_val = pll / ((pdf + 1) * (nfc_pdf + 1));
655                 break;
656         case USB_CLK:
657                 clk_sel = (cscmr1 >> 22) & 3;
658                 if (clk_sel == 0) {
659                         pll = pll_clock(PLL1);
660                 } else if (clk_sel == 1) {
661                         pll = pll_clock(PLL2);
662                 } else if (clk_sel == 2) {
663                         pll = pll_clock(PLL3);
664                 } else if (clk_sel == 3) {
665                         pll = get_lp_apm();
666                 }
667                 pdf = (cscdr1 >> 8) & 0x7;
668                 max_pdf = (cscdr1 >> 6) & 0x3;
669                 ret_val = pll / ((pdf + 1) * (max_pdf + 1));
670                 break;
671         default:
672                 diag_printf("Unknown clock: %d\n", clk);
673                 return ERR_WRONG_CLK;
674         }
675
676         return ret_val;
677 }
678
679 /*!
680  * This function returns the peripheral clock value in Hz.
681  */
682 u32 get_peri_clock(enum peri_clocks clk)
683 {
684         u32 ret_val = 0, pdf, pre_pdf, clk_sel;
685         u32 cscmr1 = readl(CCM_BASE_ADDR + CLKCTL_CSCMR1);
686         u32 cscdr1 = readl(CCM_BASE_ADDR + CLKCTL_CSCDR1);
687         u32 cscdr2 = readl(CCM_BASE_ADDR + CLKCTL_CSCDR2);
688         u32 cs1cdr = readl(CCM_BASE_ADDR + CLKCTL_CS1CDR);
689         u32 cs2cdr = readl(CCM_BASE_ADDR + CLKCTL_CS2CDR);
690
691         dbg("%s: \n", __FUNCTION__);
692         switch (clk) {
693         case UART1_BAUD:
694         case UART2_BAUD:
695         case UART3_BAUD:
696                 pre_pdf = (cscdr1 >> 3) & 0x7;
697                 pdf = cscdr1 & 0x7;
698                 clk_sel = (cscmr1 >> 24) & 3;
699                 if (clk_sel == 0) {
700                         ret_val = pll_clock(PLL1) / ((pre_pdf + 1) * (pdf + 1));
701                 } else if (clk_sel == 1) {
702                         ret_val = pll_clock(PLL2) / ((pre_pdf + 1) * (pdf + 1));
703                 } else if (clk_sel == 2) {
704                         ret_val = pll_clock(PLL3) / ((pre_pdf + 1) * (pdf + 1));
705                 } else {
706                         ret_val = get_lp_apm() / ((pre_pdf + 1) * (pdf + 1));
707                 }
708                 break;
709         case SSI1_BAUD:
710                 pre_pdf = (cs1cdr >> 6) & 0x7;
711                 pdf = cs1cdr & 0x3F;
712                 clk_sel = (cscmr1 >> 14) & 3;
713                 if (clk_sel == 0) {
714                         ret_val = pll_clock(PLL1) / ((pre_pdf + 1) * (pdf + 1));
715                 } else if (clk_sel == 0x1) {
716                         ret_val = pll_clock(PLL2) / ((pre_pdf + 1) * (pdf + 1));
717                 } else if (clk_sel == 0x2) {
718                         ret_val = pll_clock(PLL3) / ((pre_pdf + 1) * (pdf + 1));
719                 } else {
720                         ret_val = CKIH /((pre_pdf + 1) * (pdf + 1));
721                 }
722                 break;
723         case SSI2_BAUD:
724                 pre_pdf = (cs2cdr >> 6) & 0x7;
725                 pdf = cs2cdr & 0x3F;
726                 clk_sel = (cscmr1 >> 12) & 3;
727                 if (clk_sel == 0) {
728                         ret_val = pll_clock(PLL1) / ((pre_pdf + 1) * (pdf + 1));
729                 } else if (clk_sel == 0x1) {
730                         ret_val = pll_clock(PLL2) / ((pre_pdf + 1) * (pdf + 1));
731                 } else if (clk_sel == 0x2) {
732                         ret_val = pll_clock(PLL3) / ((pre_pdf + 1) * (pdf + 1));
733                 } else {
734                         ret_val = CKIH /((pre_pdf + 1) * (pdf + 1));
735                 }
736                 break;
737         case SPI1_CLK:
738         case SPI2_CLK:
739                 pre_pdf = (cscdr2 >> 25) & 0x7;
740                 pdf = (cscdr2 >> 19) & 0x3F;
741                 clk_sel = (cscmr1 >> 4) & 3;
742                 if (clk_sel == 0) {
743                         ret_val = pll_clock(PLL1) / ((pre_pdf + 1) * (pdf + 1));
744                 } else if (clk_sel == 1) {
745                         ret_val = pll_clock(PLL2) / ((pre_pdf + 1) * (pdf + 1));
746                 } else if (clk_sel == 2) {
747                         ret_val = pll_clock(PLL3) / ((pre_pdf + 1) * (pdf + 1));
748                 } else {
749                         ret_val = get_lp_apm() / ((pre_pdf + 1) * (pdf + 1));
750                 }
751                 break;
752         default:
753                 diag_printf("%s(): This clock: %d not supported yet\n",
754                                         __FUNCTION__, clk);
755         }
756
757         return ret_val;
758 }
759
760 #ifdef L2CC_ENABLED
761 /*
762  * This command is added for some simple testing only. It turns on/off
763  * L2 cache regardless of L1 cache state. The side effect of this is
764  * when doing any flash operations such as "fis init", the L2
765  * will be turned back on along with L1 caches even though it is off
766  * by using this command.
767  */
768 RedBoot_cmd("L2",
769                         "L2 cache",
770                         "[ON | OFF]",
771                         do_L2_caches
772         );
773
774 void do_L2_caches(int argc, char *argv[])
775 {
776         u32 oldints;
777
778         if (argc == 2) {
779                 if (strcasecmp(argv[1], "on") == 0) {
780                         HAL_DISABLE_INTERRUPTS(oldints);
781                         HAL_ENABLE_L2();
782                         HAL_RESTORE_INTERRUPTS(oldints);
783                 } else if (strcasecmp(argv[1], "off") == 0) {
784                         HAL_DISABLE_INTERRUPTS(oldints);
785                         HAL_DCACHE_DISABLE_L1();
786                         HAL_CACHE_FLUSH_ALL();
787                         HAL_DISABLE_L2();
788                         HAL_DCACHE_ENABLE_L1();
789                         HAL_RESTORE_INTERRUPTS(oldints);
790                 } else {
791                         diag_printf("Invalid L2 cache mode: %s\n", argv[1]);
792                 }
793         } else {
794                 int L2cache_on;
795
796                 HAL_L2CACHE_IS_ENABLED(L2cache_on);
797                 diag_printf("L2 cache: %s\n", L2cache_on ? "On" : "Off");
798         }
799 }
800 #endif //L2CC_ENABLED
801
802 #define IIM_ERR_SHIFT           8
803 #define POLL_FUSE_PRGD          (IIM_STAT_PRGD | (IIM_ERR_PRGE << IIM_ERR_SHIFT))
804 #define POLL_FUSE_SNSD          (IIM_STAT_SNSD | (IIM_ERR_SNSE << IIM_ERR_SHIFT))
805
806 static void fuse_op_start(void)
807 {
808         /* Do not generate interrupt */
809         writel(0, IIM_BASE_ADDR + IIM_STATM_OFF);
810         // clear the status bits and error bits
811         writel(0x3, IIM_BASE_ADDR + IIM_STAT_OFF);
812         writel(0xFE, IIM_BASE_ADDR + IIM_ERR_OFF);
813 }
814
815 /*
816  * The action should be either:
817  *          POLL_FUSE_PRGD
818  * or:
819  *          POLL_FUSE_SNSD
820  */
821 static int poll_fuse_op_done(int action)
822 {
823         u32 status, error;
824
825         if (action != POLL_FUSE_PRGD && action != POLL_FUSE_SNSD) {
826                 diag_printf("%s(%d) invalid operation\n", __FUNCTION__, action);
827                 return -1;
828         }
829
830         /* Poll busy bit till it is NOT set */
831         while ((readl(IIM_BASE_ADDR + IIM_STAT_OFF) & IIM_STAT_BUSY) != 0 ) {
832         }
833
834         /* Test for successful write */
835         status = readl(IIM_BASE_ADDR + IIM_STAT_OFF);
836         error = readl(IIM_BASE_ADDR + IIM_ERR_OFF);
837
838         if ((status & action) != 0 && (error & (action >> IIM_ERR_SHIFT)) == 0) {
839                 if (error) {
840                         diag_printf("Even though the operation seems successful...\n");
841                         diag_printf("There are some error(s) at addr=0x%08lx: 0x%08x\n",
842                                                 (IIM_BASE_ADDR + IIM_ERR_OFF), error);
843                 }
844                 return 0;
845         }
846         diag_printf("%s(%d) failed\n", __FUNCTION__, action);
847         diag_printf("status address=0x%08lx, value=0x%08x\n",
848                                 (IIM_BASE_ADDR + IIM_STAT_OFF), status);
849         diag_printf("There are some error(s) at addr=0x%08lx: 0x%08x\n",
850                                 (IIM_BASE_ADDR + IIM_ERR_OFF), error);
851         return -1;
852 }
853
854 unsigned int sense_fuse(int bank, int row, int bit)
855 {
856         int addr, addr_l, addr_h, reg_addr;
857
858         fuse_op_start();
859
860         addr = ((bank << 11) | (row << 3) | (bit & 0x7));
861         /* Set IIM Program Upper Address */
862         addr_h = (addr >> 8) & 0x000000FF;
863         /* Set IIM Program Lower Address */
864         addr_l = (addr & 0x000000FF);
865
866 #ifdef IIM_FUSE_DEBUG
867         diag_printf("%s: addr_h=0x%02x, addr_l=0x%02x\n",
868                                 __FUNCTION__, addr_h, addr_l);
869 #endif
870         writel(addr_h, IIM_BASE_ADDR + IIM_UA_OFF);
871         writel(addr_l, IIM_BASE_ADDR + IIM_LA_OFF);
872         /* Start sensing */
873         writel(0x8, IIM_BASE_ADDR + IIM_FCTL_OFF);
874         if (poll_fuse_op_done(POLL_FUSE_SNSD) != 0) {
875                 diag_printf("%s(bank: %d, row: %d, bit: %d failed\n",
876                                         __FUNCTION__, bank, row, bit);
877         }
878         reg_addr = IIM_BASE_ADDR + IIM_SDAT_OFF;
879         diag_printf("fuses at (bank:%d, row:%d) = 0x%08x\n", bank, row, readl(reg_addr));
880         return readl(reg_addr);
881 }
882
883 void do_fuse_read(int argc, char *argv[])
884 {
885         unsigned long bank, row;
886         unsigned long fuse_val;
887
888         if (argc == 1) {
889                 diag_printf("Usage: fuse_read <bank> <row>\n");
890                 return;
891         } else if (argc == 3) {
892                 if (!parse_num(*(&argv[1]), &bank, &argv[1], " ")) {
893                         diag_printf("Error: Invalid parameter\n");
894                         return;
895                 }
896                 if (!parse_num(*(&argv[2]), &row, &argv[2], " ")) {
897                         diag_printf("Error: Invalid parameter\n");
898                         return;
899                 }
900
901                 diag_printf("Read fuse at bank:%ld row:%ld\n", bank, row);
902                 fuse_val = sense_fuse(bank, row, 0);
903                 diag_printf("fuses at (bank:%ld, row:%ld) = 0x%lx\n", bank, row, fuse_val);
904         } else {
905                 diag_printf("Passing in wrong arguments: %d\n", argc);
906                 diag_printf("Usage: fuse_read <bank> <row>\n");
907         }
908 }
909
910 /* Blow fuses based on the bank, row and bit positions (all 0-based)
911 */
912 static int fuse_blow(int bank, int row, int bit)
913 {
914         int addr, addr_l, addr_h, ret = -1;
915
916         fuse_op_start();
917
918         /* Disable IIM Program Protect */
919         writel(0xAA, IIM_BASE_ADDR + IIM_PREG_P_OFF);
920
921         addr = ((bank << 11) | (row << 3) | (bit & 0x7));
922         /* Set IIM Program Upper Address */
923         addr_h = (addr >> 8) & 0x000000FF;
924         /* Set IIM Program Lower Address */
925         addr_l = (addr & 0x000000FF);
926
927 #ifdef IIM_FUSE_DEBUG
928         diag_printf("blowing fuse %d %d bit %d addr_h=0x%02x, addr_l=0x%02x\n",
929                                 bank, row, bit, addr_h, addr_l);
930 #endif
931
932         writel(addr_h, IIM_BASE_ADDR + IIM_UA_OFF);
933         writel(addr_l, IIM_BASE_ADDR + IIM_LA_OFF);
934         /* Start Programming */
935         writel(0x71, IIM_BASE_ADDR + IIM_FCTL_OFF);
936         if (poll_fuse_op_done(POLL_FUSE_PRGD) == 0) {
937                 ret = 0;
938         }
939
940         /* Enable IIM Program Protect */
941         writel(0x0, IIM_BASE_ADDR + IIM_PREG_P_OFF);
942         return ret;
943 }
944
945 /*
946  * This command is added for burning IIM fuses
947  */
948 RedBoot_cmd("fuse_read",
949                         "read some fuses",
950                         "<bank> <row>",
951                         do_fuse_read
952         );
953
954 RedBoot_cmd("fuse_blow",
955                         "blow some fuses",
956                         "<bank> <row> <value>",
957                         do_fuse_blow
958         );
959
960 void quick_itoa(u32 num, char *a)
961 {
962         int i, j, k;
963         for (i = 0; i <= 7; i++) {
964                 j = (num >> (4 * i)) & 0xF;
965                 k = (j < 10) ? '0' : ('a' - 0xa);
966                 a[i] = j + k;
967         }
968 }
969
970 // slen - streng length, e.g.: 23 -> slen=2; abcd -> slen=4
971 // only convert hex value as string input. so "12" is 0x12.
972 u32 quick_atoi(char *a, u32 slen)
973 {
974         u32 i, num = 0, digit;
975
976         for (i = 0; i < slen; i++) {
977                 if (a[i] >= '0' && a[i] <= '9') {
978                         digit = a[i] - '0';
979                 } else if (a[i] >= 'a' && a[i] <= 'f') {
980                         digit = a[i] - 'a' + 10;
981                 } else if (a[i] >= 'A' && a[i] <= 'F') {
982                         digit = a[i] - 'A' + 10;
983                 } else {
984                         diag_printf("ERROR: %c\n", a[i]);
985                         return -1;
986                 }
987                 num = (num * 16) + digit;
988         }
989         return num;
990 }
991
992 void fuse_blow_row(int bank, int row, int value)
993 {
994         unsigned int reg, i;
995
996         // enable fuse blown
997         reg = readl(CCM_BASE_ADDR + 0x64);
998         reg |= 0x10;
999         writel(reg, CCM_BASE_ADDR + 0x64);
1000
1001         for (i = 0; i < 8; i++) {
1002                 if (((value >> i) & 0x1) == 0) {
1003                         continue;
1004                 }
1005                 if (fuse_blow(bank, row, i) != 0) {
1006                         diag_printf("fuse_blow(bank: %d, row: %d, bit: %d failed\n",
1007                                                 bank, row, i);
1008                 }
1009         }
1010         reg &= ~0x10;
1011         writel(reg, CCM_BASE_ADDR + 0x64);
1012 }
1013
1014 void do_fuse_blow(int argc, char *argv[])
1015 {
1016         unsigned long bank, row, value, i;
1017         unsigned int fuse_val;
1018         char *s;
1019         char val[3];
1020
1021         if (argc == 1) {
1022                 diag_printf("It is too dangeous for you to use this command.\n");
1023                 return;
1024         }
1025
1026         if (argc == 3) {
1027                 if (strcasecmp(argv[1], "scc") == 0) {
1028                         // fuse_blow scc C3D153EDFD2EA9982226EF5047D3B9A0B9C7138EA87C028401D28C2C2C0B9AA2
1029                         diag_printf("Ready to burn SCC fuses\n");
1030                         s=argv[2];
1031                         for (i = 0; ;i++) {
1032                                 memcpy(val, s, 2);
1033                                 val[2]='\0';
1034                                 value = quick_atoi(val, 2);
1035                                 //    diag_printf("fuse_blow_row(2, %d, value=0x%02x)\n", i, value);
1036                                 fuse_blow_row(2, i, value);
1037
1038                                 if ((++s)[0] == '\0') {
1039                                         diag_printf("ERROR: Odd string input\n");
1040                                         break;
1041                                 }
1042                                 if ((++s)[0] == '\0') {
1043                                         diag_printf("Successful\n");
1044                                         break;
1045                                 }
1046                         }
1047                 } else if (strcasecmp(argv[1], "srk") == 0) {
1048                         // fuse_blow srk 418bccd09b53bee1ab59e2662b3c7877bc0094caee201052add49be8780dff95
1049                         diag_printf("Ready to burn SRK key fuses\n");
1050                         s=argv[2];
1051                         for (i = 0; ;i++) {
1052                                 memcpy(val, s, 2);
1053                                 val[2]='\0';
1054                                 value = quick_atoi(val, 2);
1055                                 if (i == 0) {
1056                                         fuse_blow_row(1, 1, value); // 0x41 goes to SRK_HASH[255:248], bank 1, row 1
1057                                 } else
1058                                         fuse_blow_row(3, i, value);  // 0x8b in SRK_HASH[247:240] bank 3, row 1
1059                                                                                                  // 0xcc in SRK_HASH[239:232] bank 3, row 2
1060                                                                                                  // ...
1061                                 if ((++s)[0] == '\0') {
1062                                         diag_printf("ERROR: Odd string input\n");
1063                                         break;
1064                                 }
1065                                 if ((++s)[0] == '\0') {
1066                                         diag_printf("Successful\n");
1067                                         break;
1068                                 }
1069                         }
1070                 } else
1071                         diag_printf("This command is not supported\n");
1072
1073                 return;
1074         } else if (argc == 4) {
1075                 if (!parse_num(*(&argv[1]), (unsigned long *)&bank, &argv[1], " ")) {
1076                         diag_printf("Error: Invalid parameter\n");
1077                         return;
1078                 }
1079                 if (!parse_num(*(&argv[2]), &row, &argv[2], " ")) {
1080                         diag_printf("Error: Invalid parameter\n");
1081                         return;
1082                 }
1083                 if (!parse_num(*(&argv[3]), &value, &argv[3], " ")) {
1084                         diag_printf("Error: Invalid parameter\n");
1085                         return;
1086                 }
1087
1088                 diag_printf("Blowing fuse at bank:%ld row:%ld value:%ld\n",
1089                                         bank, row, value);
1090                 fuse_blow_row(bank, row, value);
1091                 fuse_val = sense_fuse(bank, row, 0);
1092                 diag_printf("fuses at (bank:%ld, row:%ld) = 0x%02x\n", bank, row, fuse_val);
1093
1094         } else {
1095                 diag_printf("Passing in wrong arguments: %d\n", argc);
1096         }
1097 }
1098
1099 /* precondition: m>0 and n>0.  Let g=gcd(m,n). */
1100 int gcd(int m, int n)
1101 {
1102         int t;
1103         while(m > 0) {
1104                 if(n > m) {t = m; m = n; n = t;} /* swap */
1105                 m -= n;
1106         }
1107         return n;
1108 }
1109
1110 int read_mac_addr_from_fuse(unsigned char* data)
1111 {
1112         data[0] = sense_fuse(1, 9, 0) ;
1113         data[1] = sense_fuse(1, 10, 0) ;
1114         data[2] = sense_fuse(1, 11, 0) ;
1115         data[3] = sense_fuse(1, 12, 0) ;
1116         data[4] = sense_fuse(1, 13, 0) ;
1117         data[5] = sense_fuse(1, 14, 0) ;
1118
1119         if ((data[0] == 0) && (data[1] == 0) && (data[2] == 0) &&
1120                 (data[3] == 0) && (data[4] == 0) && (data[5] == 0)) {
1121                 return 0;
1122         }
1123
1124         return 1;
1125 }
1126
1127 #if 0
1128 void imx_power_mode(int mode)
1129 {
1130         volatile unsigned int val;
1131         switch (mode) {
1132         case 2:
1133                 writel(0x0000030f, GPC_PGR);
1134                 writel(0x1, SRPGCR_EMI);
1135                 writel(0x1, SRPGCR_ARM);
1136                 writel(0x1, PGC_PGCR_VPU);
1137                 writel(0x1, PGC_PGCR_IPU);
1138
1139
1140         case 1:
1141                 // stop mode - from validation code
1142                 // Set DSM_INT_HOLDOFF bit in TZIC
1143                 // If the TZIC didn't write the bit then there was interrupt pending
1144                 // It will be serviced while we're in the loop
1145                 // So we write to this bit again
1146                 while (readl(INTC_BASE_ADDR + 0x14) == 0) {
1147                         writel(1, INTC_BASE_ADDR + 0x14);
1148                         // Wait few cycles
1149                         __asm("nop");
1150                         __asm("nop");
1151                         __asm("nop");
1152                         __asm("nop");
1153                         __asm("nop");
1154                         __asm("nop");
1155                         __asm("nop");
1156                 }
1157                 diag_printf("Entering stop mode\n");
1158                 val = readl(CCM_BASE_ADDR + 0x74);
1159                 val = (val & 0xfffffffc) | 0x2; // set STOP mode
1160                 writel(val, CCM_BASE_ADDR + 0x74);
1161                 val = readl(PLATFORM_LPC_REG);
1162                 writel(val | (1 << 16), PLATFORM_LPC_REG);// ENABLE DSM in ELBOW submodule of ARM platform
1163                 writel(val | (1 << 17), PLATFORM_LPC_REG);// ENABLE DSM in ELBOW submodule of ARM platform
1164                 break;
1165         }
1166
1167         hal_delay_us(50);
1168
1169         asm("mov r1, #0");
1170         asm("mcr p15, 0, r1, c7, c0, 4");
1171 }
1172
1173 void do_power_mode(int argc, char *argv[])
1174 {
1175         int mode;
1176
1177         if (argc == 1) {
1178                 diag_printf("Usage: power_mode <mode>\n");
1179                 return;
1180         } else if (argc == 2) {
1181                 if (!parse_num(*(&argv[1]), (unsigned long *)&mode, &argv[1], " ")) {
1182                         diag_printf("Error: Invalid parameter\n");
1183                         return;
1184                 }
1185                 diag_printf("Entering power mode: %d\n", mode);
1186                 imx_power_mode(mode);
1187
1188         } else {
1189                 diag_printf("Passing in wrong arguments: %d\n", argc);
1190                 diag_printf("Usage: power_mode <mode>\n");
1191         }
1192 }
1193
1194 /*
1195  * This command is added for burning IIM fuses
1196  */
1197 RedBoot_cmd("power_mode",
1198                         "Enter various power modes:",
1199                         "\n"
1200                         "           <0> - WAIT\n"
1201                         "           <1> - SRPG\n"
1202                         "           <2> - STOP\n"
1203                         "           <3> - STOP with Power-Gating\n"
1204                         "           -- need reset after issuing the command",
1205                         do_power_mode
1206         );
1207 #endif
1208
1209 /* Super Root key moduli */
1210 static const UINT8 hab_super_root_moduli[] = {
1211         /* modulus data */
1212         0xb9, 0x84, 0xc8, 0x8a, 0xd3, 0x7e, 0xcc, 0xc0, 0xe7, 0x3e, 0x11, 0x53,
1213         0x6b, 0x5e, 0xea, 0xf4, 0xd9, 0xac, 0x5a, 0x63, 0x8a, 0x79, 0x96, 0x83,
1214         0xb1, 0x39, 0xb2, 0x6f, 0x9c, 0x54, 0x87, 0xf4, 0x3b, 0x9e, 0xd8, 0x0f,
1215         0x89, 0xf5, 0x01, 0x53, 0xb8, 0xe2, 0xcc, 0x75, 0x0d, 0xe1, 0x13, 0xfa,
1216         0xa7, 0xb9, 0x1e, 0xff, 0x6a, 0x05, 0xdb, 0x58, 0x10, 0xbf, 0x2b, 0xf4,
1217         0xe7, 0x0a, 0x63, 0x82, 0x2c, 0xa3, 0xb5, 0x0a, 0x72, 0x1c, 0xdc, 0x29,
1218         0xc1, 0x81, 0xb5, 0x9a, 0xf0, 0x25, 0x7d, 0xd6, 0xee, 0x01, 0x64, 0xc7,
1219         0x07, 0x2d, 0xcb, 0x31, 0x4c, 0x8d, 0x82, 0xf6, 0x44, 0x95, 0x4a, 0xbc,
1220         0xae, 0xe8, 0x2a, 0x89, 0xd4, 0xf2, 0x66, 0x72, 0x2b, 0x09, 0x4e, 0x56,
1221         0xe9, 0xbf, 0x5e, 0x38, 0x5c, 0xd5, 0x7e, 0x15, 0x55, 0x86, 0x0f, 0x19,
1222         0xf6, 0x00, 0xee, 0xa1, 0x92, 0x78, 0xef, 0x93, 0xcb, 0xfa, 0xb4, 0x98,
1223         0x19, 0xef, 0x10, 0x70, 0xde, 0x36, 0x1c, 0x12, 0x2e, 0xd2, 0x09, 0xc7,
1224         0x7b, 0xd1, 0xaa, 0xd3, 0x46, 0x65, 0xa1, 0x5b, 0xee, 0xa5, 0x96, 0x97,
1225         0x98, 0x3e, 0xfc, 0xf8, 0x74, 0x22, 0x51, 0xe7, 0xf1, 0x2f, 0x30, 0x79,
1226         0x13, 0xe5, 0x42, 0xc6, 0x7c, 0x18, 0x76, 0xd3, 0x7f, 0x5a, 0x13, 0xde,
1227         0x2f, 0x51, 0x07, 0xfa, 0x93, 0xfe, 0x10, 0x8a, 0x0c, 0x18, 0x60, 0x3c,
1228         0xff, 0x6a, 0x9b, 0xe7, 0x10, 0x2d, 0x71, 0xd2, 0x34, 0xc0, 0xdf, 0xbe,
1229         0x17, 0x4e, 0x75, 0x40, 0x83, 0xaa, 0x90, 0xd1, 0xed, 0xbd, 0xbf, 0xac,
1230         0x9a, 0x30, 0xbd, 0x69, 0x4d, 0xd8, 0x00, 0x63, 0x92, 0x69, 0x98, 0xf8,
1231         0x89, 0xdc, 0x7b, 0xe3, 0x66, 0x7e, 0xdd, 0xfa, 0x8c, 0x74, 0xe2, 0xb1,
1232         0xeb, 0x94, 0xf7, 0xab, 0x0e, 0x92, 0x06, 0xab, 0x60, 0xe5, 0x00, 0x43,
1233         0xb2, 0x5e, 0x6e, 0xeb
1234 };
1235
1236 /* Super Root key */
1237 const hab_rsa_public_key hab_super_root_key[] = {
1238         {
1239                 {
1240                         /* RSA public exponent, right-padded */
1241                         0x01, 0x00, 0x01, 0x00,
1242                 },
1243                 /* pointer to modulus data */
1244                 hab_super_root_moduli,
1245                 /* Exponent size in bytes */
1246                 0x03,
1247                 /* Modulus size in bytes */
1248                 0x100,
1249                 /* Key data valid */
1250                 TRUE
1251         }
1252 };