]> git.karo-electronics.de Git - karo-tx-redboot.git/blob - packages/hal/arm/mx51/var/v2_0/src/cmds.c
STK5 Release 1.10
[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("AXI_A\t\tAXI_B\t\tEMI_SLOW_CLK\n");
468         diag_printf("========================================================\n");
469         diag_printf("%-16d%-16d%-16d\n\n",
470                                 get_main_clock(AXI_A_CLK),
471                                 get_main_clock(AXI_B_CLK),
472                                 get_main_clock(EMI_SLOW_CLK));
473         diag_printf("CPU\t\tAHB\t\tIPG\t\tDDR_CLK\n");
474         diag_printf("========================================================\n");
475         diag_printf("%-16d%-16d%-16d%-16d\n\n",
476                                 get_main_clock(CPU_CLK),
477                                 get_main_clock(AHB_CLK),
478                                 get_main_clock(IPG_CLK),
479                                 get_main_clock(DDR_CLK));
480
481         diag_printf("NFC\t\tUSB\t\tIPG_PER_CLK\n");
482         diag_printf("========================================\n");
483         diag_printf("%-16d%-16d%-16d\n\n",
484                                 get_main_clock(NFC_CLK),
485                                 get_main_clock(USB_CLK),
486                                 get_main_clock(IPG_PER_CLK));
487
488         diag_printf("UART1-3\t\tSSI1\t\tSSI2\t\tSPI\n");
489         diag_printf("===========================================");
490         diag_printf("=============\n");
491
492         diag_printf("%-16d%-16d%-16d%-16d\n\n",
493                                 get_peri_clock(UART1_BAUD),
494                                 get_peri_clock(SSI1_BAUD),
495                                 get_peri_clock(SSI2_BAUD),
496                                 get_peri_clock(SPI1_CLK));
497
498 #if 0
499         diag_printf("IPG_PERCLK as baud clock for: UART1-5, I2C, OWIRE, SDHC");
500         if (((readl(EPIT1_BASE_ADDR) >> 24) & 0x3) == 0x2) {
501                 diag_printf(", EPIT");
502         }
503         if (((readl(GPT1_BASE_ADDR) >> 6) & 0x7) == 0x2) {
504                 diag_printf("GPT,");
505         }
506 #endif
507         diag_printf("\n");
508
509 }
510
511 /*!
512  * This function returns the PLL output value in Hz based on pll.
513  */
514 u32 pll_clock(enum plls pll)
515 {
516         u64 ref_clk;
517         u32 mfi, mfn, mfd, pdf, pll_out, sign;
518         u32 dp_ctrl, dp_op, dp_mfd, dp_mfn;
519         int clk_sel;
520         int dbl;
521
522         dp_ctrl = pll_base[pll][PLL_DP_CTL >> 2];
523         clk_sel = MXC_GET_FIELD(dp_ctrl, 2, 8);
524         ref_clk = fixed_mfd[clk_sel].ref_clk_hz;
525
526         dbg("clk_sel=%d\n", clk_sel);
527
528         if ((pll_base[pll][PLL_DP_CTL >> 2] & 0x80) == 0) {
529                 dp_op = pll_base[pll][PLL_DP_OP >> 2];
530                 dp_mfd = pll_base[pll][PLL_DP_MFD >> 2];
531                 dp_mfn = pll_base[pll][PLL_DP_MFN >> 2];
532         } else {
533                 dp_op = pll_base[pll][PLL_DP_HFS_OP >> 2];
534                 dp_mfd = pll_base[pll][PLL_DP_HFS_MFD >> 2];
535                 dp_mfn = pll_base[pll][PLL_DP_HFS_MFN >> 2];
536         }
537         pdf = dp_op & 0xF;
538         mfi = (dp_op >> 4) & 0xF;
539         mfi = (mfi <= 5) ? 5: mfi;
540         mfd = dp_mfd & 0x07FFFFFF;
541         mfn = dp_mfn & 0x07FFFFFF;
542
543         sign = (mfn < 0x4000000) ? 1 : -1;
544         mfn = (mfn < 0x4000000) ? mfn : (0x8000000 - mfn);
545
546         dbl = 2 * (((dp_ctrl >> 12) & 0x1) + 1);
547
548         dbg("%s: ref=%llu.%03lluMHz, dbl=%d, pd=%d, mfi=%d, mfn=%s%d, mfd=%d\n",
549                 __FUNCTION__, ref_clk / 1000000, ref_clk / 1000 % 1000,
550                 dbl, pdf, mfi, sign ? "-" : "", mfn, mfd);
551
552         pll_out = (dbl * ref_clk * mfi + ((dbl * ref_clk * sign * mfn) / (mfd + 1))) /
553                 (pdf + 1);
554
555         return pll_out;
556 }
557
558 /*!
559  * This function returns the emi_core_clk_root clock.
560  */
561 u32 get_emi_core_clk(void)
562 {
563         u32 cbcdr = readl(CCM_BASE_ADDR + CLKCTL_CBCDR);
564         u32 clk_sel, max_pdf, peri_clk, ahb_clk;
565         u32 ret_val;
566
567         max_pdf = (cbcdr >> 10) & 0x7;
568         peri_clk = get_periph_clk();
569         ahb_clk = peri_clk / (max_pdf + 1);
570
571         clk_sel = (cbcdr >> 26) & 1;
572         if (clk_sel == 0) {
573                 ret_val = peri_clk;
574         } else {
575                 ret_val = ahb_clk ;
576         }
577         dbg("%s: CBCDR[%08lx]=%08x freq=%u.%03uMHz\n", __FUNCTION__,
578                 CCM_BASE_ADDR + CLKCTL_CBCDR, cbcdr, ret_val / 1000000, ret_val / 1000 % 1000);
579         return ret_val;
580 }
581
582 /*!
583  * This function returns the main clock value in Hz.
584  */
585 u32 get_main_clock(enum main_clocks clk)
586 {
587         u32 pdf, max_pdf, ipg_pdf, nfc_pdf, clk_sel;
588         u32 pll, ret_val;
589         u32 cacrr = readl(CCM_BASE_ADDR + CLKCTL_CACRR);
590         u32 cbcdr = readl(CCM_BASE_ADDR + CLKCTL_CBCDR);
591         u32 cbcmr = readl(CCM_BASE_ADDR + CLKCTL_CBCMR);
592         u32 cscmr1 = readl(CCM_BASE_ADDR + CLKCTL_CSCMR1);
593         u32 cscdr1 = readl(CCM_BASE_ADDR + CLKCTL_CSCDR1);
594
595         dbg("%s: \n", __FUNCTION__);
596         switch (clk) {
597         case CPU_CLK:
598                 pdf = cacrr & 0x7;
599                 pll = pll_clock(PLL1);
600                 ret_val = pll / (pdf + 1);
601                 break;
602
603         case AHB_CLK:
604                 max_pdf = (cbcdr >> 10) & 0x7;
605                 pll = get_periph_clk();
606                 ret_val = pll / (max_pdf + 1);
607                 break;
608
609         case AXI_A_CLK:
610                 pdf = (cbcdr >> 16) & 0x7;
611                 pll = get_periph_clk();
612                 ret_val = pll / (pdf + 1);
613                 break;
614
615         case AXI_B_CLK:
616                 pdf = (cbcdr >> 19) & 0x7;
617                 pll = get_periph_clk();
618                 ret_val = pll / (pdf + 1);
619                 break;
620
621         case EMI_SLOW_CLK:
622                 pll = get_emi_core_clk();
623                 pdf = (cbcdr >> 22) & 0x7;
624                 ret_val = pll / (pdf + 1);
625                 break;
626
627         case IPG_CLK:
628                 max_pdf = (cbcdr >> 10) & 0x7;
629                 ipg_pdf = (cbcdr >> 8) & 0x3;
630                 pll = get_periph_clk();
631                 ret_val = pll / ((max_pdf + 1) * (ipg_pdf + 1));
632                 break;
633
634         case IPG_PER_CLK:
635                 clk_sel = cbcmr & 1;
636                 if (clk_sel == 0) {
637                         clk_sel = (cbcmr >> 1) & 1;
638                         pdf = (((cbcdr >> 6) & 3) + 1) * (((cbcdr >> 3) & 7) + 1) * ((cbcdr & 7) + 1);
639                         if (clk_sel == 0) {
640                                 ret_val = get_periph_clk() / pdf;
641                         } else {
642                                 ret_val = get_lp_apm();
643                         }
644                 } else {
645                         /* Same as IPG_CLK */
646                         max_pdf = (cbcdr >> 10) & 0x7;
647                         ipg_pdf = (cbcdr >> 8) & 0x3;
648                         pll = get_periph_clk();
649                         ret_val = pll / ((max_pdf + 1) * (ipg_pdf + 1));
650                 }
651                 break;
652
653         case DDR_CLK:
654                 if (cbcdr & (1 << 30)) {
655                         pll = pll_clock(PLL1);
656                         pdf = (cbcdr >> 27) & 0x7;
657                 } else {
658                         clk_sel = (cbcmr >> 10) & 3;
659                         pll = get_periph_clk();
660                         if (clk_sel == 0) {
661                                 /* AXI A */
662                                 pdf = (cbcdr >> 16) & 0x7;
663                         } else if (clk_sel == 1) {
664                                 /* AXI B */
665                                 pdf = (cbcdr >> 19) & 0x7;
666                         } else if (clk_sel == 2) {
667                                 /* EMI SLOW CLOCK ROOT */
668                                 pll = get_emi_core_clk();
669                                 pdf = (cbcdr >> 22) & 0x7;
670                         } else if (clk_sel == 3) {
671                                 /* AHB CLOCK */
672                                 pdf = (cbcdr >> 10) & 0x7;
673                         }
674                 }
675
676                 ret_val = pll / (pdf + 1);
677                 break;
678
679         case NFC_CLK:
680                 pdf = (cbcdr >> 22) & 0x7;
681                 nfc_pdf = (cbcdr >> 13) & 0x7;
682                 pll = get_emi_core_clk();
683                 ret_val = pll / ((pdf + 1) * (nfc_pdf + 1));
684                 break;
685
686         case USB_CLK:
687                 clk_sel = (cscmr1 >> 22) & 3;
688                 if (clk_sel == 0) {
689                         pll = pll_clock(PLL1);
690                 } else if (clk_sel == 1) {
691                         pll = pll_clock(PLL2);
692                 } else if (clk_sel == 2) {
693                         pll = pll_clock(PLL3);
694                 } else if (clk_sel == 3) {
695                         pll = get_lp_apm();
696                 }
697                 pdf = (cscdr1 >> 8) & 0x7;
698                 max_pdf = (cscdr1 >> 6) & 0x3;
699                 ret_val = pll / ((pdf + 1) * (max_pdf + 1));
700                 break;
701
702         default:
703                 diag_printf("Unknown clock: %d\n", clk);
704                 return ERR_WRONG_CLK;
705         }
706
707         return ret_val;
708 }
709
710 /*!
711  * This function returns the peripheral clock value in Hz.
712  */
713 u32 get_peri_clock(enum peri_clocks clk)
714 {
715         u32 ret_val = 0, pdf, pre_pdf, clk_sel;
716         u32 cscmr1 = readl(CCM_BASE_ADDR + CLKCTL_CSCMR1);
717         u32 cscdr1 = readl(CCM_BASE_ADDR + CLKCTL_CSCDR1);
718         u32 cscdr2 = readl(CCM_BASE_ADDR + CLKCTL_CSCDR2);
719         u32 cs1cdr = readl(CCM_BASE_ADDR + CLKCTL_CS1CDR);
720         u32 cs2cdr = readl(CCM_BASE_ADDR + CLKCTL_CS2CDR);
721
722         dbg("%s: \n", __FUNCTION__);
723         switch (clk) {
724         case UART1_BAUD:
725         case UART2_BAUD:
726         case UART3_BAUD:
727                 pre_pdf = (cscdr1 >> 3) & 0x7;
728                 pdf = cscdr1 & 0x7;
729                 clk_sel = (cscmr1 >> 24) & 3;
730                 if (clk_sel == 0) {
731                         ret_val = pll_clock(PLL1) / ((pre_pdf + 1) * (pdf + 1));
732                 } else if (clk_sel == 1) {
733                         ret_val = pll_clock(PLL2) / ((pre_pdf + 1) * (pdf + 1));
734                 } else if (clk_sel == 2) {
735                         ret_val = pll_clock(PLL3) / ((pre_pdf + 1) * (pdf + 1));
736                 } else {
737                         ret_val = get_lp_apm() / ((pre_pdf + 1) * (pdf + 1));
738                 }
739                 break;
740         case SSI1_BAUD:
741                 pre_pdf = (cs1cdr >> 6) & 0x7;
742                 pdf = cs1cdr & 0x3F;
743                 clk_sel = (cscmr1 >> 14) & 3;
744                 if (clk_sel == 0) {
745                         ret_val = pll_clock(PLL1) / ((pre_pdf + 1) * (pdf + 1));
746                 } else if (clk_sel == 0x1) {
747                         ret_val = pll_clock(PLL2) / ((pre_pdf + 1) * (pdf + 1));
748                 } else if (clk_sel == 0x2) {
749                         ret_val = pll_clock(PLL3) / ((pre_pdf + 1) * (pdf + 1));
750                 } else {
751                         ret_val = CKIH /((pre_pdf + 1) * (pdf + 1));
752                 }
753                 break;
754         case SSI2_BAUD:
755                 pre_pdf = (cs2cdr >> 6) & 0x7;
756                 pdf = cs2cdr & 0x3F;
757                 clk_sel = (cscmr1 >> 12) & 3;
758                 if (clk_sel == 0) {
759                         ret_val = pll_clock(PLL1) / ((pre_pdf + 1) * (pdf + 1));
760                 } else if (clk_sel == 0x1) {
761                         ret_val = pll_clock(PLL2) / ((pre_pdf + 1) * (pdf + 1));
762                 } else if (clk_sel == 0x2) {
763                         ret_val = pll_clock(PLL3) / ((pre_pdf + 1) * (pdf + 1));
764                 } else {
765                         ret_val = CKIH /((pre_pdf + 1) * (pdf + 1));
766                 }
767                 break;
768         case SPI1_CLK:
769         case SPI2_CLK:
770                 pre_pdf = (cscdr2 >> 25) & 0x7;
771                 pdf = (cscdr2 >> 19) & 0x3F;
772                 clk_sel = (cscmr1 >> 4) & 3;
773                 if (clk_sel == 0) {
774                         ret_val = pll_clock(PLL1) / ((pre_pdf + 1) * (pdf + 1));
775                 } else if (clk_sel == 1) {
776                         ret_val = pll_clock(PLL2) / ((pre_pdf + 1) * (pdf + 1));
777                 } else if (clk_sel == 2) {
778                         ret_val = pll_clock(PLL3) / ((pre_pdf + 1) * (pdf + 1));
779                 } else {
780                         ret_val = get_lp_apm() / ((pre_pdf + 1) * (pdf + 1));
781                 }
782                 break;
783         default:
784                 diag_printf("%s(): This clock: %d not supported yet\n",
785                                         __FUNCTION__, clk);
786         }
787
788         return ret_val;
789 }
790
791 #ifdef L2CC_ENABLED
792 /*
793  * This command is added for some simple testing only. It turns on/off
794  * L2 cache regardless of L1 cache state. The side effect of this is
795  * when doing any flash operations such as "fis init", the L2
796  * will be turned back on along with L1 caches even though it is off
797  * by using this command.
798  */
799 RedBoot_cmd("L2",
800                         "L2 cache",
801                         "[ON | OFF]",
802                         do_L2_caches
803         );
804
805 void do_L2_caches(int argc, char *argv[])
806 {
807         u32 oldints;
808
809         if (argc == 2) {
810                 if (strcasecmp(argv[1], "on") == 0) {
811                         HAL_DISABLE_INTERRUPTS(oldints);
812                         HAL_ENABLE_L2();
813                         HAL_RESTORE_INTERRUPTS(oldints);
814                 } else if (strcasecmp(argv[1], "off") == 0) {
815                         HAL_DISABLE_INTERRUPTS(oldints);
816                         HAL_DCACHE_DISABLE_L1();
817                         HAL_CACHE_FLUSH_ALL();
818                         HAL_DISABLE_L2();
819                         HAL_DCACHE_ENABLE_L1();
820                         HAL_RESTORE_INTERRUPTS(oldints);
821                 } else {
822                         diag_printf("Invalid L2 cache mode: %s\n", argv[1]);
823                 }
824         } else {
825                 int L2cache_on;
826
827                 HAL_L2CACHE_IS_ENABLED(L2cache_on);
828                 diag_printf("L2 cache: %s\n", L2cache_on ? "On" : "Off");
829         }
830 }
831 #endif //L2CC_ENABLED
832
833 #define IIM_ERR_SHIFT           8
834 #define POLL_FUSE_PRGD          (IIM_STAT_PRGD | (IIM_ERR_PRGE << IIM_ERR_SHIFT))
835 #define POLL_FUSE_SNSD          (IIM_STAT_SNSD | (IIM_ERR_SNSE << IIM_ERR_SHIFT))
836
837 static void fuse_op_start(void)
838 {
839         /* Do not generate interrupt */
840         writel(0, IIM_BASE_ADDR + IIM_STATM_OFF);
841         // clear the status bits and error bits
842         writel(0x3, IIM_BASE_ADDR + IIM_STAT_OFF);
843         writel(0xFE, IIM_BASE_ADDR + IIM_ERR_OFF);
844 }
845
846 /*
847  * The action should be either:
848  *          POLL_FUSE_PRGD
849  * or:
850  *          POLL_FUSE_SNSD
851  */
852 static int poll_fuse_op_done(int action)
853 {
854         u32 status, error;
855
856         if (action != POLL_FUSE_PRGD && action != POLL_FUSE_SNSD) {
857                 diag_printf("%s(%d) invalid operation\n", __FUNCTION__, action);
858                 return -1;
859         }
860
861         /* Poll busy bit till it is NOT set */
862         while ((readl(IIM_BASE_ADDR + IIM_STAT_OFF) & IIM_STAT_BUSY) != 0 ) {
863         }
864
865         /* Test for successful write */
866         status = readl(IIM_BASE_ADDR + IIM_STAT_OFF);
867         error = readl(IIM_BASE_ADDR + IIM_ERR_OFF);
868
869         if ((status & action) != 0 && (error & (action >> IIM_ERR_SHIFT)) == 0) {
870                 if (error) {
871                         diag_printf("Even though the operation seems successful...\n");
872                         diag_printf("There are some error(s) at addr=0x%08lx: 0x%08x\n",
873                                                 (IIM_BASE_ADDR + IIM_ERR_OFF), error);
874                 }
875                 return 0;
876         }
877         diag_printf("%s(%d) failed\n", __FUNCTION__, action);
878         diag_printf("status address=0x%08lx, value=0x%08x\n",
879                                 (IIM_BASE_ADDR + IIM_STAT_OFF), status);
880         diag_printf("There are some error(s) at addr=0x%08lx: 0x%08x\n",
881                                 (IIM_BASE_ADDR + IIM_ERR_OFF), error);
882         return -1;
883 }
884
885 unsigned int sense_fuse(int bank, int row, int bit)
886 {
887         int addr, addr_l, addr_h, reg_addr;
888
889         fuse_op_start();
890
891         addr = ((bank << 11) | (row << 3) | (bit & 0x7));
892         /* Set IIM Program Upper Address */
893         addr_h = (addr >> 8) & 0x000000FF;
894         /* Set IIM Program Lower Address */
895         addr_l = (addr & 0x000000FF);
896
897 #ifdef IIM_FUSE_DEBUG
898         diag_printf("%s: addr_h=0x%02x, addr_l=0x%02x\n",
899                                 __FUNCTION__, addr_h, addr_l);
900 #endif
901         writel(addr_h, IIM_BASE_ADDR + IIM_UA_OFF);
902         writel(addr_l, IIM_BASE_ADDR + IIM_LA_OFF);
903         /* Start sensing */
904         writel(0x8, IIM_BASE_ADDR + IIM_FCTL_OFF);
905         if (poll_fuse_op_done(POLL_FUSE_SNSD) != 0) {
906                 diag_printf("%s(bank: %d, row: %d, bit: %d failed\n",
907                                         __FUNCTION__, bank, row, bit);
908         }
909         reg_addr = IIM_BASE_ADDR + IIM_SDAT_OFF;
910         diag_printf("fuses at (bank:%d, row:%d) = 0x%08x\n", bank, row, readl(reg_addr));
911         return readl(reg_addr);
912 }
913
914 void do_fuse_read(int argc, char *argv[])
915 {
916         unsigned long bank, row;
917         unsigned long fuse_val;
918
919         if (argc == 1) {
920                 diag_printf("Usage: fuse_read <bank> <row>\n");
921                 return;
922         } else if (argc == 3) {
923                 if (!parse_num(*(&argv[1]), &bank, &argv[1], " ")) {
924                         diag_printf("Error: Invalid parameter\n");
925                         return;
926                 }
927                 if (!parse_num(*(&argv[2]), &row, &argv[2], " ")) {
928                         diag_printf("Error: Invalid parameter\n");
929                         return;
930                 }
931
932                 diag_printf("Read fuse at bank:%ld row:%ld\n", bank, row);
933                 fuse_val = sense_fuse(bank, row, 0);
934                 diag_printf("fuses at (bank:%ld, row:%ld) = 0x%lx\n", bank, row, fuse_val);
935         } else {
936                 diag_printf("Passing in wrong arguments: %d\n", argc);
937                 diag_printf("Usage: fuse_read <bank> <row>\n");
938         }
939 }
940
941 /* Blow fuses based on the bank, row and bit positions (all 0-based)
942 */
943 static int fuse_blow(int bank, int row, int bit)
944 {
945         int addr, addr_l, addr_h, ret = -1;
946
947         fuse_op_start();
948
949         /* Disable IIM Program Protect */
950         writel(0xAA, IIM_BASE_ADDR + IIM_PREG_P_OFF);
951
952         addr = ((bank << 11) | (row << 3) | (bit & 0x7));
953         /* Set IIM Program Upper Address */
954         addr_h = (addr >> 8) & 0x000000FF;
955         /* Set IIM Program Lower Address */
956         addr_l = (addr & 0x000000FF);
957
958 #ifdef IIM_FUSE_DEBUG
959         diag_printf("blowing fuse %d %d bit %d addr_h=0x%02x, addr_l=0x%02x\n",
960                                 bank, row, bit, addr_h, addr_l);
961 #endif
962
963         writel(addr_h, IIM_BASE_ADDR + IIM_UA_OFF);
964         writel(addr_l, IIM_BASE_ADDR + IIM_LA_OFF);
965         /* Start Programming */
966         writel(0x71, IIM_BASE_ADDR + IIM_FCTL_OFF);
967         if (poll_fuse_op_done(POLL_FUSE_PRGD) == 0) {
968                 ret = 0;
969         }
970
971         /* Enable IIM Program Protect */
972         writel(0x0, IIM_BASE_ADDR + IIM_PREG_P_OFF);
973         return ret;
974 }
975
976 /*
977  * This command is added for burning IIM fuses
978  */
979 RedBoot_cmd("fuse_read",
980                         "read some fuses",
981                         "<bank> <row>",
982                         do_fuse_read
983         );
984
985 RedBoot_cmd("fuse_blow",
986                         "blow some fuses",
987                         "<bank> <row> <value>",
988                         do_fuse_blow
989         );
990
991 void quick_itoa(u32 num, char *a)
992 {
993         int i, j, k;
994         for (i = 0; i <= 7; i++) {
995                 j = (num >> (4 * i)) & 0xF;
996                 k = (j < 10) ? '0' : ('a' - 0xa);
997                 a[i] = j + k;
998         }
999 }
1000
1001 // slen - streng length, e.g.: 23 -> slen=2; abcd -> slen=4
1002 // only convert hex value as string input. so "12" is 0x12.
1003 u32 quick_atoi(char *a, u32 slen)
1004 {
1005         u32 i, num = 0, digit;
1006
1007         for (i = 0; i < slen; i++) {
1008                 if (a[i] >= '0' && a[i] <= '9') {
1009                         digit = a[i] - '0';
1010                 } else if (a[i] >= 'a' && a[i] <= 'f') {
1011                         digit = a[i] - 'a' + 10;
1012                 } else if (a[i] >= 'A' && a[i] <= 'F') {
1013                         digit = a[i] - 'A' + 10;
1014                 } else {
1015                         diag_printf("ERROR: %c\n", a[i]);
1016                         return -1;
1017                 }
1018                 num = (num * 16) + digit;
1019         }
1020         return num;
1021 }
1022
1023 void fuse_blow_row(int bank, int row, int value)
1024 {
1025         unsigned int reg, i;
1026
1027         // enable fuse blown
1028         reg = readl(CCM_BASE_ADDR + 0x64);
1029         reg |= 0x10;
1030         writel(reg, CCM_BASE_ADDR + 0x64);
1031
1032         for (i = 0; i < 8; i++) {
1033                 if (((value >> i) & 0x1) == 0) {
1034                         continue;
1035                 }
1036                 if (fuse_blow(bank, row, i) != 0) {
1037                         diag_printf("fuse_blow(bank: %d, row: %d, bit: %d failed\n",
1038                                                 bank, row, i);
1039                 }
1040         }
1041         reg &= ~0x10;
1042         writel(reg, CCM_BASE_ADDR + 0x64);
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]), (unsigned long *)&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 int gcd(int m, int n)
1132 {
1133         int t;
1134         while(m > 0) {
1135                 if(n > m) {t = m; m = n; n = t;} /* swap */
1136                 m -= n;
1137         }
1138         return n;
1139 }
1140
1141 int read_mac_addr_from_fuse(unsigned char* data)
1142 {
1143         data[0] = sense_fuse(1, 9, 0) ;
1144         data[1] = sense_fuse(1, 10, 0) ;
1145         data[2] = sense_fuse(1, 11, 0) ;
1146         data[3] = sense_fuse(1, 12, 0) ;
1147         data[4] = sense_fuse(1, 13, 0) ;
1148         data[5] = sense_fuse(1, 14, 0) ;
1149
1150         if ((data[0] == 0) && (data[1] == 0) && (data[2] == 0) &&
1151                 (data[3] == 0) && (data[4] == 0) && (data[5] == 0)) {
1152                 return 0;
1153         }
1154
1155         return 1;
1156 }
1157
1158 #if 0
1159 void imx_power_mode(int mode)
1160 {
1161         volatile unsigned int val;
1162         switch (mode) {
1163         case 2:
1164                 writel(0x0000030f, GPC_PGR);
1165                 writel(0x1, SRPGCR_EMI);
1166                 writel(0x1, SRPGCR_ARM);
1167                 writel(0x1, PGC_PGCR_VPU);
1168                 writel(0x1, PGC_PGCR_IPU);
1169
1170
1171         case 1:
1172                 // stop mode - from validation code
1173                 // Set DSM_INT_HOLDOFF bit in TZIC
1174                 // If the TZIC didn't write the bit then there was interrupt pending
1175                 // It will be serviced while we're in the loop
1176                 // So we write to this bit again
1177                 while (readl(INTC_BASE_ADDR + 0x14) == 0) {
1178                         writel(1, INTC_BASE_ADDR + 0x14);
1179                         // Wait few cycles
1180                         __asm("nop");
1181                         __asm("nop");
1182                         __asm("nop");
1183                         __asm("nop");
1184                         __asm("nop");
1185                         __asm("nop");
1186                         __asm("nop");
1187                 }
1188                 diag_printf("Entering stop mode\n");
1189                 val = readl(CCM_BASE_ADDR + 0x74);
1190                 val = (val & 0xfffffffc) | 0x2; // set STOP mode
1191                 writel(val, CCM_BASE_ADDR + 0x74);
1192                 val = readl(PLATFORM_LPC_REG);
1193                 writel(val | (1 << 16), PLATFORM_LPC_REG);// ENABLE DSM in ELBOW submodule of ARM platform
1194                 writel(val | (1 << 17), PLATFORM_LPC_REG);// ENABLE DSM in ELBOW submodule of ARM platform
1195                 break;
1196         }
1197
1198         hal_delay_us(50);
1199
1200         asm("mov r1, #0");
1201         asm("mcr p15, 0, r1, c7, c0, 4");
1202 }
1203
1204 void do_power_mode(int argc, char *argv[])
1205 {
1206         int mode;
1207
1208         if (argc == 1) {
1209                 diag_printf("Usage: power_mode <mode>\n");
1210                 return;
1211         } else if (argc == 2) {
1212                 if (!parse_num(*(&argv[1]), (unsigned long *)&mode, &argv[1], " ")) {
1213                         diag_printf("Error: Invalid parameter\n");
1214                         return;
1215                 }
1216                 diag_printf("Entering power mode: %d\n", mode);
1217                 imx_power_mode(mode);
1218
1219         } else {
1220                 diag_printf("Passing in wrong arguments: %d\n", argc);
1221                 diag_printf("Usage: power_mode <mode>\n");
1222         }
1223 }
1224
1225 /*
1226  * This command is added for burning IIM fuses
1227  */
1228 RedBoot_cmd("power_mode",
1229                         "Enter various power modes:",
1230                         "\n"
1231                         "           <0> - WAIT\n"
1232                         "           <1> - SRPG\n"
1233                         "           <2> - STOP\n"
1234                         "           <3> - STOP with Power-Gating\n"
1235                         "           -- need reset after issuing the command",
1236                         do_power_mode
1237         );
1238 #endif
1239
1240 /* Super Root key moduli */
1241 static const UINT8 hab_super_root_moduli[] = {
1242         /* modulus data */
1243         0xb9, 0x84, 0xc8, 0x8a, 0xd3, 0x7e, 0xcc, 0xc0, 0xe7, 0x3e, 0x11, 0x53,
1244         0x6b, 0x5e, 0xea, 0xf4, 0xd9, 0xac, 0x5a, 0x63, 0x8a, 0x79, 0x96, 0x83,
1245         0xb1, 0x39, 0xb2, 0x6f, 0x9c, 0x54, 0x87, 0xf4, 0x3b, 0x9e, 0xd8, 0x0f,
1246         0x89, 0xf5, 0x01, 0x53, 0xb8, 0xe2, 0xcc, 0x75, 0x0d, 0xe1, 0x13, 0xfa,
1247         0xa7, 0xb9, 0x1e, 0xff, 0x6a, 0x05, 0xdb, 0x58, 0x10, 0xbf, 0x2b, 0xf4,
1248         0xe7, 0x0a, 0x63, 0x82, 0x2c, 0xa3, 0xb5, 0x0a, 0x72, 0x1c, 0xdc, 0x29,
1249         0xc1, 0x81, 0xb5, 0x9a, 0xf0, 0x25, 0x7d, 0xd6, 0xee, 0x01, 0x64, 0xc7,
1250         0x07, 0x2d, 0xcb, 0x31, 0x4c, 0x8d, 0x82, 0xf6, 0x44, 0x95, 0x4a, 0xbc,
1251         0xae, 0xe8, 0x2a, 0x89, 0xd4, 0xf2, 0x66, 0x72, 0x2b, 0x09, 0x4e, 0x56,
1252         0xe9, 0xbf, 0x5e, 0x38, 0x5c, 0xd5, 0x7e, 0x15, 0x55, 0x86, 0x0f, 0x19,
1253         0xf6, 0x00, 0xee, 0xa1, 0x92, 0x78, 0xef, 0x93, 0xcb, 0xfa, 0xb4, 0x98,
1254         0x19, 0xef, 0x10, 0x70, 0xde, 0x36, 0x1c, 0x12, 0x2e, 0xd2, 0x09, 0xc7,
1255         0x7b, 0xd1, 0xaa, 0xd3, 0x46, 0x65, 0xa1, 0x5b, 0xee, 0xa5, 0x96, 0x97,
1256         0x98, 0x3e, 0xfc, 0xf8, 0x74, 0x22, 0x51, 0xe7, 0xf1, 0x2f, 0x30, 0x79,
1257         0x13, 0xe5, 0x42, 0xc6, 0x7c, 0x18, 0x76, 0xd3, 0x7f, 0x5a, 0x13, 0xde,
1258         0x2f, 0x51, 0x07, 0xfa, 0x93, 0xfe, 0x10, 0x8a, 0x0c, 0x18, 0x60, 0x3c,
1259         0xff, 0x6a, 0x9b, 0xe7, 0x10, 0x2d, 0x71, 0xd2, 0x34, 0xc0, 0xdf, 0xbe,
1260         0x17, 0x4e, 0x75, 0x40, 0x83, 0xaa, 0x90, 0xd1, 0xed, 0xbd, 0xbf, 0xac,
1261         0x9a, 0x30, 0xbd, 0x69, 0x4d, 0xd8, 0x00, 0x63, 0x92, 0x69, 0x98, 0xf8,
1262         0x89, 0xdc, 0x7b, 0xe3, 0x66, 0x7e, 0xdd, 0xfa, 0x8c, 0x74, 0xe2, 0xb1,
1263         0xeb, 0x94, 0xf7, 0xab, 0x0e, 0x92, 0x06, 0xab, 0x60, 0xe5, 0x00, 0x43,
1264         0xb2, 0x5e, 0x6e, 0xeb
1265 };
1266
1267 /* Super Root key */
1268 const hab_rsa_public_key hab_super_root_key[] = {
1269         {
1270                 {
1271                         /* RSA public exponent, right-padded */
1272                         0x01, 0x00, 0x01, 0x00,
1273                 },
1274                 /* pointer to modulus data */
1275                 hab_super_root_moduli,
1276                 /* Exponent size in bytes */
1277                 0x03,
1278                 /* Modulus size in bytes */
1279                 0x100,
1280                 /* Key data valid */
1281                 TRUE
1282         }
1283 };