1 //==========================================================================
5 // SoC [platform] specific RedBoot commands
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.
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.
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
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.
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.
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.
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 //==========================================================================
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>
47 typedef unsigned long long u64;
48 typedef unsigned int u32;
49 typedef unsigned short u16;
50 typedef unsigned char u8;
52 #define SZ_DEC_1M 1000000
53 #define PLL_PD_MAX 16 //actual pd+1
54 #define PLL_MFI_MAX 15
56 #define PLL_MFD_MAX 1024 //actual mfd+1
57 #define PLL_MFN_MAX 511
60 #define HSP_PODF_MAX 8
61 #define NFC_PODF_MAX 8
63 #if (PLL_REF_CLK == FREQ_32768HZ) || (PLL_REF_CLK == FREQ_32000HZ)
64 #define PLL_MFD_FIXED 1024
66 #if (PLL_REF_CLK == FREQ_26MHZ)
67 #define PLL_MFD_FIXED (26 * 16) // =416
70 #define PLL_FREQ_MAX (2 * PLL_REF_CLK * PLL_MFI_MAX)
71 #define TPLL_FREQ_MAX 390000000
72 #define PLL_FREQ_MIN ((2 * PLL_REF_CLK * (PLL_MFI_MIN - 1)) / PLL_PD_MAX)
73 #define AHB_CLK_MAX 133000000
74 #define IPG_CLK_MAX (AHB_CLK_MAX / 2)
75 #define NFC_CLK_MAX 25000000
76 // IPU-HSP clock is independent of the HCLK and can go up to 177MHz but requires
77 // higher voltage support. For simplicity, limit it to 133MHz
78 #define HSP_CLK_MAX 133333333
80 #define ERR_WRONG_CLK -1
84 #define ERR_NO_AHB_DIV -6
86 u32 pll_clock(enum plls pll);
87 u32 get_main_clock(enum main_clocks clk);
88 u32 get_peri_clock(enum peri_clocks clk);
89 int poll_fuse_set(void);
90 int gcd(int m, int n);
92 static void clock_setup(int argc, char *argv[]);
93 static void ckol(int argc, char *argv[]);
94 static void ckoh(int argc, char *argv[]);
97 "Setup/Display clock (max AHB=133MHz, max IPG=66.5MHz)\nSyntax:",
98 "[<core clock in MHz> [:<AHB-to-core divider>[:<IPG-to-AHB divider>]]] \n\n\
99 If a divider is zero or no divider is specified, the optimal divider values \n\
100 will be chosen. It does NOT do integer freq scaling so no brmm value changes.\n\
101 Instead, it always adjusts the PLL settings. \n\
103 [clock] -> Show various clocks\n\
104 [clock 399] -> Core=399 AHB=133 IPG=66.5\n\
105 [clock 200] -> Core=200 AHB=100 IPG=50\n\
106 [clock 399:6] -> Core=399 AHB=66.5(Core/6) IPG=66.5\n\
107 [clock 399:6:2] -> Core=399 AHB=66.5(Core/6) IPG=33.25(AHB/2)\n",
112 * This is to calculate various parameters based on reference clock and
113 * targeted clock based on the equation:
114 * t_clk = 2*ref_freq*(mfi + mfn/(mfd+1))/(pd+1)
115 * This calculation is based on a fixed MFD value for simplicity.
117 * @param ref reference clock freq
118 * @param target targeted clock in HZ
119 * @param p_pd calculated pd value (pd value from register + 1) upon return
120 * @param p_mfi calculated actual mfi value upon return
121 * @param p_mfn calculated actual mfn value upon return
122 * @param p_mfd fixed mfd value (mfd value from register + 1) upon return
124 * @return 0 if successful; non-zero otherwise.
126 int calc_pll_params(u32 ref, u32 target, u32 *p_pd,
127 u32 *p_mfi, u32 *p_mfn, u32 *p_mfd)
129 u64 pd, mfi, mfn, n_target = (u64)target, n_ref = (u64)ref;
131 // Make sure targeted freq is in the valid range. Otherwise the
132 // following calculation might be wrong!!!
133 if (target < PLL_FREQ_MIN || target > PLL_FREQ_MAX) {
134 return ERR_WRONG_CLK;
136 // Use n_target and n_ref to avoid overflow
137 for (pd = 1; pd <= PLL_PD_MAX; pd++) {
138 mfi = (n_target * pd) / (2 * n_ref);
139 if (mfi > PLL_MFI_MAX) {
141 } else if (mfi < 5) {
146 // Now got pd and mfi already
147 mfn = (((n_target * pd) / 2 - n_ref * mfi) * PLL_MFD_FIXED) / n_ref;
148 // Check mfn within limit and mfn < denominator
149 if (mfn > PLL_MFN_MAX || mfn >= PLL_MFD_FIXED) {
153 if (pd > PLL_PD_MAX) {
159 *p_mfd = PLL_MFD_FIXED;
164 * This function assumes the expected core clock has to be changed by
165 * modifying the PLL. This is NOT true always but for most of the times,
166 * it is. So it assumes the PLL output freq is the same as the expected
167 * core clock (presc=1) unless the core clock is less than PLL_FREQ_MIN.
168 * In the latter case, it will try to increase the presc value until
169 * (presc*core_clk) is greater than PLL_FREQ_MIN. It then makes call to
170 * calc_pll_params() and obtains the values of PD, MFI,MFN, MFD based
171 * on the targeted PLL and reference input clock to the PLL. Lastly,
172 * it sets the register based on these values along with the dividers.
173 * Note 1) There is no value checking for the passed-in divider values
174 * so the caller has to make sure those values are sensible.
175 * 2) Also adjust the NFC divider such that the NFC clock doesn't
176 * exceed NFC_CLK_MAX.
177 * 3) IPU HSP clock is independent of AHB clock. Even it can go up to
178 * 177MHz for higher voltage, this function fixes the max to 133MHz.
179 * 4) This function should not have allowed diag_printf() calls since
180 * the serial driver has been stoped. But leave then here to allow
181 * easy debugging by NOT calling the cyg_hal_plf_serial_stop().
183 * @param ref pll input reference clock (32KHz or 26MHz)
184 * @param core_clk core clock in Hz
185 * @param ahb_div ahb divider to divide the core clock to get ahb clock
186 * (ahb_div - 1) needs to be set in the register
187 * @param ipg_div ipg divider to divide the ahb clock to get ipg clock
188 * (ipg_div - 1) needs to be set in the register
189 # @return 0 if successful; non-zero otherwise
191 int configure_clock(u32 ref, u32 core_clk, u32 ahb_div, u32 ipg_div)
193 u32 pll, pd, mfi, mfn, mfd, brmo = 0, pctl0;
194 u32 pdr0, nfc_div, ahb_clk = core_clk / ahb_div;
197 // assume pll default to core clock first
199 // when core_clk >= PLL_FREQ_MIN, the presc can be 1.
200 // Otherwise, need to calculate presc value below and adjust the targeted pll
201 if (core_clk < PLL_FREQ_MIN) {
202 diag_printf("can't make core_clk=%d\n", core_clk);
203 return ERR_WRONG_CLK;
206 // get nfc_div - make sure optimal NFC clock but less than NFC_CLK_MAX
207 for (nfc_div = 1; nfc_div <= NFC_PODF_MAX; nfc_div++) {
208 if ((pll / (ahb_div * nfc_div)) <= NFC_CLK_MAX) {
213 // pll is now the targeted pll output. Use it along with ref input clock
214 // to get pd, mfi, mfn, mfd
215 if ((ret = calc_pll_params(ref, pll, &pd, &mfi, &mfn, &mfd)) != 0) {
216 diag_printf("can't find pll parameters: %d\n", ret);
219 #ifdef CMD_CLOCK_DEBUG
220 diag_printf("ref=%d, pll=%d, pd=%d, mfi=%d,mfn=%d, mfd=%d\n",
221 ref, pll, pd, mfi, mfn, mfd);
224 // blindly increase divider first to avoid too fast ahbclk and ipgclk
225 // in case the core clock increases too much
226 pdr0 = readl(CRM_MCU_BASE_ADDR + CLKCTL_PDR0);
228 // increase the dividers. should work even when core clock is 832 (26*2*16)MHz
229 // which is unlikely true.
230 pdr0 |= (1 << 6) | (6 << 3);
231 writel(pdr0, CRM_MCU_BASE_ADDR + CLKCTL_PDR0);
232 // calculate new pdr0. Also clear the brmm bits
234 pdr0 |= ((nfc_div - 1) << 8) | ((ipg_div - 1) << 6) | ((ahb_div - 1) << 3);
236 // update PLL register
237 if ((mfd >= (10 * mfn)) || ((10 * mfn) >= (9 * mfd)))
240 pctl0 = readl(CRM_MCU_BASE_ADDR + CLKCTL_MPCTL);
241 pctl0 = (pctl0 & 0x40008000) |
247 writel(pctl0, CRM_MCU_BASE_ADDR + CLKCTL_MPCTL);
248 writel(pdr0, CRM_MCU_BASE_ADDR + CLKCTL_PDR0);
249 // add some delay for new values to take effect
250 for (i = 0; i < 10000; i++);
252 // --------------- now adjust for TPLL ---------------------------
253 pll = (TPLL_FREQ_MAX / ahb_clk) * ahb_clk;
254 if ((ret = calc_pll_params(ref, pll, &pd, &mfi, &mfn, &mfd)) != 0) {
255 diag_printf("can't find tpll parameters: %d\n", ret);
258 #ifdef CMD_CLOCK_DEBUG
259 diag_printf("ref=%d, pll=%d, pd=%d, mfi=%d,mfn=%d, mfd=%d\n",
260 ref, pll, pd, mfi, mfn, mfd);
263 // update PLL register
264 if ((mfd >= (10 * mfn)) || ((10 * mfn) >= (9 * mfd)))
267 pctl0 = readl(CRM_MCU_BASE_ADDR + CLKCTL_TPCTL);
268 pctl0 = (pctl0 & 0x40008000) |
274 writel(pctl0, CRM_MCU_BASE_ADDR + CLKCTL_TPCTL);
279 static void clock_setup(int argc,char *argv[])
281 u32 i, core_clk, ipg_div, data[3],
282 ahb_div, ahb_clk, ipg_clk;
287 for (i = 0; i < 3; i++) {
289 if (!parse_num(*(&argv[1]), &temp, &argv[1], ":")) {
290 diag_printf("Error: Invalid parameter\n");
296 core_clk = data[0] * SZ_DEC_1M;
297 ahb_div = data[1]; // actual register field + 1
298 ipg_div = data[2]; // actual register field + 1
300 if (core_clk < PLL_FREQ_MIN || core_clk > PLL_FREQ_MAX) {
301 diag_printf("Targeted core clock should be within [%d - %d]\n",
302 PLL_FREQ_MIN, PLL_FREQ_MAX);
306 // find the ahb divider
307 if (ahb_div > AHB_DIV_MAX) {
308 diag_printf("Invalid AHB divider: %d. Maximum value is %d\n",
309 ahb_div, AHB_DIV_MAX);
313 // no HCLK divider specified
314 for (ahb_div = 1; ; ahb_div++) {
315 if ((core_clk / ahb_div) <= AHB_CLK_MAX) {
320 if (ahb_div > AHB_DIV_MAX || (core_clk / ahb_div) > AHB_CLK_MAX) {
321 diag_printf("Can't make AHB=%d since max=%d\n",
322 core_clk / ahb_div, AHB_CLK_MAX);
326 // find the ipg divider
327 ahb_clk = core_clk / ahb_div;
328 if (ipg_div > IPG_DIV_MAX) {
329 diag_printf("Invalid IPG divider: %d. Maximum value is %d\n",
330 ipg_div, IPG_DIV_MAX);
334 ipg_div++; // At least =1
335 if (ahb_clk > IPG_CLK_MAX)
336 ipg_div++; // Make it =2
338 if (ipg_div > IPG_DIV_MAX || (ahb_clk / ipg_div) > IPG_CLK_MAX) {
339 diag_printf("Can't make IPG=%d since max=%d\n",
340 (ahb_clk / ipg_div), IPG_CLK_MAX);
343 ipg_clk = ahb_clk / ipg_div;
345 diag_printf("Trying to set core=%d ahb=%d ipg=%d...\n",
346 core_clk, ahb_clk, ipg_clk);
348 // stop the serial to be ready to adjust the clock
349 hal_delay_us(100000);
350 cyg_hal_plf_serial_stop();
352 ret = configure_clock(PLL_REF_CLK, core_clk, ahb_div, ipg_div);
353 // restart the serial driver
354 cyg_hal_plf_serial_init();
355 hal_delay_us(100000);
358 diag_printf("Failed to setup clock: %d\n", ret);
361 diag_printf("\n<<<New clock setting>>>\n");
363 // Now printing clocks
366 diag_printf("\nMPLL\t\tUPLL\t\tTPLL\n");
367 diag_printf("================================================\n");
368 diag_printf("%-16d%-16d%-16d\n\n",
369 pll_clock(MCU_PLL), pll_clock(USB_PLL), pll_clock(TUR_PLL));
372 diag_printf("CPU\t\tAHB\t\tIPG\t\tNFC\t\tUSB\n");
373 diag_printf("===========================================");
374 diag_printf("=============================\n");
375 diag_printf("%-16d%-16d%-16d%-16d%-16d\n\n",
376 get_main_clock(CPU_CLK),
377 get_main_clock(AHB_CLK),
378 get_main_clock(IPG_CLK),
379 get_main_clock(NFC_CLK),
380 get_main_clock(USB_CLK));
382 diag_printf("UART2/3/4\tSSI1\t\tCSI\n");
383 diag_printf("===========================================\n");
385 diag_printf("%-16d%-16d%-16d\n\n",
386 get_peri_clock(UART2_BAUD),
387 get_peri_clock(SSI1_BAUD),
388 get_peri_clock(CSI_BAUD));
392 * This function returns the PLL output value in Hz based on pll.
394 u32 pll_clock(enum plls pll)
396 u64 mfi, mfn, mfd, pdf, ref_clk, pll_out, sign;
397 u64 reg = readl(pll);
399 pdf = (reg >> 26) & 0xF;
400 mfd = (reg >> 16) & 0x3FF;
401 if (pll == MCU_PLL || pll == TUR_PLL) {
402 mfi = (reg >> 11) & 0xF;
403 mfi = (mfi <= 5) ? 5: mfi;
405 sign = (mfn < 1024) ? 0: 1;
406 mfn = (mfn <= 0x400) ? mfn: (0x800 - mfn);
409 mfi = (reg >> 10) & 0xF;
410 mfi = (mfi <= 5) ? 5: mfi;
414 /* Scale down to avoid overflow */
415 ref_clk = PLL_REF_CLK;
417 diag_printf("Error: fix input clock first for %s() to work\n",
423 pll_out = (2 * ref_clk * mfi + ((2 * ref_clk * mfn) / (mfd + 1))) /
426 pll_out = (2 * ref_clk * mfi - ((2 * ref_clk * mfn) / (mfd + 1))) /
433 #define NORMALIZE_FACTOR 10
435 void clock_spi_enable(unsigned int spi_clk)
437 if (spi_clk == SPI1_CLK) {
438 // do nothing now as it is already enabled by default
443 * This function returns the main clock value in Hz.
445 u32 get_main_clock(enum main_clocks clk)
447 u32 brmm, max_pdf, ipg_pdf, nfc_pdf, csi_pdf;
448 u32 pll, ret_val = 0, hclk, usb_pdf, div;
449 enum plls CORE_PLL_SEL = MCU_PLL;
451 volatile u32 reg = readl(CRM_MCU_BASE_ADDR + CLKCTL_PDR0);
452 volatile u32 reg1 = readl(CRM_MCU_BASE_ADDR + CLKCTL_PDR1);
454 max_pdf = (reg >> 3) & 0x7;
455 ipg_pdf = (reg >> 6) & 0x3;
456 nfc_pdf = (reg >> 8) & 0x7;
458 usb_pdf = (reg1 >> 27) & 0x7;
460 if ((readl(CRM_MCU_BASE_ADDR + CLKCTL_PDR0) & (1 << 11)) != 0) {
461 CORE_PLL_SEL = TUR_PLL;
466 pll = pll_clock(CORE_PLL_SEL);
468 diag_printf("Wrong BRMM value in the CRM_AP, MPDR0 reg \n");
471 hclk = pll / (max_pdf + 1);
472 div = (pll * NORMALIZE_FACTOR) / hclk;
478 // new period = (2*MCU_period + 1*AHB_period)/3
479 // => new freq = (3*pll*hclk)/(2*hclk+pll)
480 // => new frq = (3*pll)/(2+pll/hclk). Also normalize it.
481 ret_val = (3* pll * NORMALIZE_FACTOR) /
482 ((2 * NORMALIZE_FACTOR) + ((pll * NORMALIZE_FACTOR) / hclk));
485 // new period = (1*MCU_period + 1*AHB_period)/2
486 // => new freq = (2*pll*hclk)/(hclk+pll)
487 // => new frq = (2*pll)/(1+pll/hclk). Also normalize it.
488 ret_val = (2* pll * NORMALIZE_FACTOR) /
489 ((1 * NORMALIZE_FACTOR) + ((pll * NORMALIZE_FACTOR) / hclk));
492 // new period = (1*MCU_period + 2*AHB_period)/3
493 // => new freq = (3*pll*hclk)/(hclk+2*pll)
494 // => new frq = (3*pll)/(1+(2*pll)/hclk). Also normalize it.
495 ret_val = (3* pll * NORMALIZE_FACTOR) /
496 ((1 * NORMALIZE_FACTOR) + ((2 * pll * NORMALIZE_FACTOR) / hclk));
506 pll = pll_clock(CORE_PLL_SEL);
507 ret_val = pll / (max_pdf + 1);
510 pll = pll_clock(CORE_PLL_SEL);
511 ret_val = pll / ((max_pdf + 1) * (ipg_pdf + 1));
514 pll = pll_clock(CORE_PLL_SEL);
515 ret_val = pll / ((max_pdf + 1) * (nfc_pdf + 1));
518 pll = pll_clock(USB_PLL);
519 ret_val = pll / (usb_pdf + 1);
522 diag_printf("%s(): This clock: %d not supported yet \n",
530 static u32 csi_sdhc_clock_src(u32 clksrc)
536 val = pll_clock(USB_PLL);
539 val = pll_clock(MCU_PLL);
542 val = pll_clock(TUR_PLL);
553 * This function returns the peripheral clock value in Hz.
555 u32 get_peri_clock(enum peri_clocks clk)
557 volatile u32 mcr = readl(CRM_MCU_BASE_ADDR + CLKCTL_MCR);
558 volatile u32 mpdr0 = readl(CRM_MCU_BASE_ADDR + CLKCTL_PDR0);
559 volatile u32 mpdr1 = readl(CRM_MCU_BASE_ADDR + CLKCTL_PDR1);
560 u32 clk_sel, pre_pdf, pdf, ref_clk, ret_val = 0;
566 return get_main_clock(IPG_CLK);
569 pre_pdf = (mpdr1 >> 6) & 0x7;
570 pdf = (mpdr1 >> 1) & 0x1F;
571 clk_sel = mcr & (1 << 28);
572 ref_clk = (clk_sel != 0) ? pll_clock(USB_PLL) : pll_clock(MCU_PLL);
573 ret_val = ref_clk / ((pre_pdf + 1) * (pdf + 1));
576 clk_sel = (mcr >> 25) & 0x3;
577 pdf = ((mpdr0 >> 23) & 0x1FF) + 1;
578 pdf = (2 * pdf) + (mpdr0 & (1 << 22)); //multiplied by 2
579 pdf *= (1 + (mpdr0 & (1 << 21)));
581 ret_val = (2 * csi_sdhc_clock_src(clk_sel)) / pdf;
585 ret_val = get_main_clock(IPG_CLK);
588 diag_printf("%s(): This clock: %d not supported yet \n",
597 "Select clock source for CKO1 (AKA CKO) (J10 on the EVB CPU daughter card)",
598 " The output is 1/8 of actual clock. Default is MCU_PLL\n\
599 <0> - display current cko selection\n\
607 <8> - MB_PAT_REF \n",
611 static u8* cko_name[] = {
623 #define CKO_MAX_INDEX (sizeof(cko_name) / sizeof(u8*))
624 #define CKO_DIV 3 // default divide by 8
625 #define CKOH_DIV 3 // default divide by 8
627 static void ckol(int argc,char *argv[])
629 u32 action = 0, cosr;
631 if (!scan_opts(argc, argv, 1, 0, 0, (void*) &action,
632 OPTION_ARG_TYPE_NUM, "action"))
635 if (action >= CKO_MAX_INDEX) {
636 diag_printf("%d is not supported\n\n", action);
640 cosr = readl(CRM_MCU_BASE_ADDR + CLKCTL_COSR);
643 cosr = (cosr & (~0x7F)) + (1 << 6) + (CKO_DIV << 3) + action - 1;
644 writel(cosr, CRM_MCU_BASE_ADDR + CLKCTL_COSR);
645 diag_printf("Set clko to ");
648 cosr = readl(CRM_MCU_BASE_ADDR + CLKCTL_COSR);
649 diag_printf("%s\n", cko_name[(cosr & 0x7) + 1]);
650 diag_printf("COSR register[0x%x] = 0x%x\n",
651 (CRM_MCU_BASE_ADDR + CLKCTL_COSR), cosr);
655 "Select clock source for CKO2 (J9 on the EVB CPU daughter card)",
656 " The default is 1/8 of IPG_CLK_ARM (core clock)\n\
657 <0> - display current cko selection\n\
667 <10> - MCU_AHB_CLK \n\
670 <13> - DSP_AHB_CLK \n\
671 <14> - IPG_CLK_ARM (Core) \n\
672 <15> - PAT_REF_CLK_SYNC \n\
673 <16> - WB_PAT_REF_CLK_SYNC \n\
679 static u8* div_str[] = {
690 static u8* ckoh_name[] ={
705 "IPG_CLK_ARM (Core)",
707 "WB_PAT_REF_CLK_SYNC",
712 #define CKOH_MAX_INDEX (sizeof(ckoh_name) / sizeof(u8*))
714 static void ckoh(int argc,char *argv[])
716 u32 action = 0, cosr, div = 0, i, j;
718 if (!scan_opts(argc, argv, 1, 0, 0, (void*) &action,
719 OPTION_ARG_TYPE_NUM, "action"))
722 if (action >= CKOH_MAX_INDEX) {
723 diag_printf("%d is not supported\n\n", action);
727 cosr = readl(CRM_MCU_BASE_ADDR + CLKCTL_COSR);
730 if (action == 1 || action == 3 || action == 4 || action == 5 || action == 14 || action == 17)
732 cosr = (cosr & (~0x0007FC00)) + (div << 10) + (1 << 13) +
733 ((action - 1) << 14);
734 writel(cosr, CRM_MCU_BASE_ADDR + CLKCTL_COSR);
735 diag_printf("Set clko to ");
738 cosr = readl(CRM_MCU_BASE_ADDR + CLKCTL_COSR);
739 i = (cosr >> 10) & 0x7;
740 j = (cosr >> 14) & 0x1F;
741 diag_printf("%s%s\n", div_str[i], ckoh_name[j + 1]);
742 diag_printf("COSR register[0x%x] = 0x%x\n",
743 (CRM_MCU_BASE_ADDR + CLKCTL_COSR), cosr);
746 #define IIM_ERR_SHIFT 8
747 #define POLL_FUSE_PRGD (IIM_STAT_PRGD | (IIM_ERR_PRGE << IIM_ERR_SHIFT))
748 #define POLL_FUSE_SNSD (IIM_STAT_SNSD | (IIM_ERR_SNSE << IIM_ERR_SHIFT))
750 static void fuse_op_start(void)
752 /* Do not generate interrupt */
753 writel(0, IIM_BASE_ADDR + IIM_STATM_OFF);
754 // clear the status bits and error bits
755 writel(0x3, IIM_BASE_ADDR + IIM_STAT_OFF);
756 writel(0xFE, IIM_BASE_ADDR + IIM_ERR_OFF);
760 * The action should be either:
765 static int poll_fuse_op_done(int action)
770 if (action != POLL_FUSE_PRGD && action != POLL_FUSE_SNSD) {
771 diag_printf("%s(%d) invalid operation\n", __FUNCTION__, action);
775 /* Poll busy bit till it is NOT set */
776 while ((readl(IIM_BASE_ADDR + IIM_STAT_OFF) & IIM_STAT_BUSY) != 0 ) {
779 /* Test for successful write */
780 status = readl(IIM_BASE_ADDR + IIM_STAT_OFF);
781 error = readl(IIM_BASE_ADDR + IIM_ERR_OFF);
783 if ((status & action) != 0 && (error & (action >> IIM_ERR_SHIFT)) == 0) {
785 diag_printf("Even though the operation seems successful...\n");
786 diag_printf("There are some error(s) at addr=0x%x: 0x%x\n",
787 (IIM_BASE_ADDR + IIM_ERR_OFF), error);
791 diag_printf("%s(%d) failed\n", __FUNCTION__, action);
792 diag_printf("status address=0x%x, value=0x%x\n",
793 (IIM_BASE_ADDR + IIM_STAT_OFF), status);
794 diag_printf("There are some error(s) at addr=0x%x: 0x%x\n",
795 (IIM_BASE_ADDR + IIM_ERR_OFF), error);
799 unsigned int sense_fuse(int bank, int row, int bit)
801 int addr, addr_l, addr_h, reg_addr;
805 addr = ((bank << 11) | (row << 3) | (bit & 0x7));
806 /* Set IIM Program Upper Address */
807 addr_h = (addr >> 8) & 0x000000FF;
808 /* Set IIM Program Lower Address */
809 addr_l = (addr & 0x000000FF);
811 #ifdef IIM_FUSE_DEBUG
812 diag_printf("%s: addr_h=0x%x, addr_l=0x%x\n",
813 __FUNCTION__, addr_h, addr_l);
815 writel(addr_h, IIM_BASE_ADDR + IIM_UA_OFF);
816 writel(addr_l, IIM_BASE_ADDR + IIM_LA_OFF);
818 writel(0x8, IIM_BASE_ADDR + IIM_FCTL_OFF);
819 if (poll_fuse_op_done(POLL_FUSE_SNSD) != 0) {
820 diag_printf("%s(bank: %d, row: %d, bit: %d failed\n",
821 __FUNCTION__, bank, row, bit);
823 reg_addr = IIM_BASE_ADDR + IIM_SDAT_OFF;
824 diag_printf("fuses at (bank:%d, row:%d) = 0x%x\n", bank, row, readl(reg_addr));
826 return readl(reg_addr);
829 void do_fuse_read(int argc, char *argv[])
834 diag_printf("Useage: fuse_read <bank> <row>\n");
836 } else if (argc == 3) {
837 if (!parse_num(*(&argv[1]), (unsigned long *)&bank, &argv[1], " ")) {
838 diag_printf("Error: Invalid parameter\n");
841 if (!parse_num(*(&argv[2]), (unsigned long *)&row, &argv[2], " ")) {
842 diag_printf("Error: Invalid parameter\n");
846 diag_printf("Read fuse at bank:%d row:%d\n", bank, row);
847 sense_fuse(bank, row, 0);
850 diag_printf("Passing in wrong arguments: %d\n", argc);
851 diag_printf("Useage: fuse_read <bank> <row>\n");
855 /* Blow fuses based on the bank, row and bit positions (all 0-based)
857 static int fuse_blow(int bank,int row,int bit)
859 int addr, addr_l, addr_h, ret = -1;
863 /* Disable IIM Program Protect */
864 writel(0xAA, IIM_BASE_ADDR + IIM_PREG_P_OFF);
866 addr = ((bank << 11) | (row << 3) | (bit & 0x7));
867 /* Set IIM Program Upper Address */
868 addr_h = (addr >> 8) & 0x000000FF;
869 /* Set IIM Program Lower Address */
870 addr_l = (addr & 0x000000FF);
872 #ifdef IIM_FUSE_DEBUG
873 diag_printf("blowing addr_h=0x%x, addr_l=0x%x\n", addr_h, addr_l);
876 writel(addr_h, IIM_BASE_ADDR + IIM_UA_OFF);
877 writel(addr_l, IIM_BASE_ADDR + IIM_LA_OFF);
878 /* Start Programming */
879 writel(0x31, IIM_BASE_ADDR + IIM_FCTL_OFF);
880 if (poll_fuse_op_done(POLL_FUSE_PRGD) == 0) {
884 /* Enable IIM Program Protect */
885 writel(0x0, IIM_BASE_ADDR + IIM_PREG_P_OFF);
890 * This command is added for burning IIM fuses
892 RedBoot_cmd("fuse_read",
898 RedBoot_cmd("fuse_blow",
900 "<bank> <row> <value>",
904 #define INIT_STRING "12345678"
905 static char ready_to_blow[] = INIT_STRING;
907 void quick_itoa(u32 num, char *a)
910 for (i = 0; i <= 7; i++) {
911 j = (num >> (4 * i)) & 0xF;
912 k = (j < 10) ? '0' : ('a' - 0xa);
917 void do_fuse_blow(int argc, char *argv[])
919 int bank, row, value, i;
922 diag_printf("It is too dangeous for you to use this command.\n");
924 } else if (argc == 2) {
925 if (strcasecmp(argv[1], "nandboot") == 0) {
926 quick_itoa(readl(EPIT_BASE_ADDR + EPITCNR), ready_to_blow);
927 diag_printf("%s\n", ready_to_blow);
930 } else if (argc == 3) {
931 if (strcasecmp(argv[1], "nandboot") == 0 &&
932 strcasecmp(argv[2], ready_to_blow) == 0) {
933 #if defined(CYGPKG_HAL_ARM_MXC91131) || defined(CYGPKG_HAL_ARM_MX21) || defined(CYGPKG_HAL_ARM_MX27) || defined(CYGPKG_HAL_ARM_MX31)
934 diag_printf("No need to blow any fuses for NAND boot on this platform\n\n");
936 diag_printf("Ready to burn NAND boot fuses\n");
937 if (fuse_blow(0, 16, 1) != 0 || fuse_blow(0, 16, 7) != 0) {
938 diag_printf("NAND BOOT fuse blown failed miserably ...\n");
940 diag_printf("NAND BOOT fuse blown successfully ...\n");
943 diag_printf("Not ready: %s, %s\n", argv[1], argv[2]);
946 } else if (argc == 4) {
947 if (!parse_num(*(&argv[1]), (unsigned long *)&bank, &argv[1], " ")) {
948 diag_printf("Error: Invalid parameter\n");
951 if (!parse_num(*(&argv[2]), (unsigned long *)&row, &argv[2], " ")) {
952 diag_printf("Error: Invalid parameter\n");
955 if (!parse_num(*(&argv[3]), (unsigned long *)&value, &argv[3], " ")) {
956 diag_printf("Error: Invalid parameter\n");
960 diag_printf("Blowing fuse at bank:%d row:%d value:%d\n",
962 for (i = 0; i < 8; i++) {
963 if (((value >> i) & 0x1) == 0) {
966 if (fuse_blow(bank, row, i) != 0) {
967 diag_printf("fuse_blow(bank: %d, row: %d, bit: %d failed\n",
970 diag_printf("fuse_blow(bank: %d, row: %d, bit: %d successful\n",
974 sense_fuse(bank, row, 0);
977 diag_printf("Passing in wrong arguments: %d\n", argc);
979 /* Reset to default string */
980 strcpy(ready_to_blow, INIT_STRING);;
983 /* precondition: m>0 and n>0. Let g=gcd(m,n). */
984 int gcd(int m, int n)
988 if(n > m) {t = m; m = n; n = t;} /* swap */