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 534000000
72 #define PLL_FREQ_MIN ((2 * PLL_REF_CLK * (PLL_MFI_MIN - 1)) / PLL_PD_MAX)
73 #define AHB_CLK_MAX 133333333
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
365 #ifdef CYGPKG_HAL_ARM_MXC91321_CHIP
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("UART1/2/3/4\tSSI1\t\tSSI2\t\tCSI\t\tFIRI\n");
383 diag_printf("===========================================");
384 diag_printf("=============================\n");
386 diag_printf("%-16d%-16d%-16d%-16d%-16d\n\n",
387 get_peri_clock(UART1_BAUD),
388 get_peri_clock(SSI1_BAUD),
389 get_peri_clock(SSI2_BAUD),
390 get_peri_clock(CSI_BAUD),
391 get_peri_clock(FIRI_BAUD));
395 * This function returns the PLL output value in Hz based on pll.
397 u32 pll_clock(enum plls pll)
399 u64 mfi, mfn, mfd, pdf, ref_clk, pll_out, sign;
400 u64 reg = readl(pll);
402 pdf = (reg >> 26) & 0xF;
403 mfd = (reg >> 16) & 0x3FF;
404 if (pll == MCU_PLL || pll == TUR_PLL) {
405 mfi = (reg >> 11) & 0xF;
406 mfi = (mfi <= 5) ? 5: mfi;
408 sign = (mfn < 1024) ? 0: 1;
409 mfn = (mfn <= 0x400) ? mfn: (0x800 - mfn);
412 mfi = (reg >> 10) & 0xF;
413 mfi = (mfi <= 5) ? 5: mfi;
417 /* Scale down to avoid overflow */
418 ref_clk = PLL_REF_CLK;
420 diag_printf("Error: fix input clock first for %s() to work\n",
426 pll_out = (2 * ref_clk * mfi + ((2 * ref_clk * mfn) / (mfd + 1))) /
429 pll_out = (2 * ref_clk * mfi - ((2 * ref_clk * mfn) / (mfd + 1))) /
436 #define NORMALIZE_FACTOR 10
438 void clock_spi_enable(unsigned int spi_clk)
440 if (spi_clk == SPI1_CLK) {
441 // do nothing now as it is already enabled by default
442 } else if (spi_clk == SPI2_CLK) {
443 // do nothing now as it is already enabled by default
448 * This function returns the main clock value in Hz.
450 u32 get_main_clock(enum main_clocks clk)
452 u32 brmm, max_pdf, ipg_pdf, nfc_pdf, csi_pdf;
453 u32 pll, ret_val = 0, hclk, usb_pdf, div;
454 enum plls CORE_PLL_SEL = MCU_PLL;
456 volatile u32 reg = readl(CRM_MCU_BASE_ADDR + CLKCTL_PDR0);
457 volatile u32 reg1 = readl(CRM_MCU_BASE_ADDR + CLKCTL_PDR1);
459 max_pdf = (reg >> 3) & 0x7;
460 ipg_pdf = (reg >> 6) & 0x3;
461 nfc_pdf = (reg >> 8) & 0x7;
463 usb_pdf = (reg1 >> 27) & 0x7;
465 #ifdef CYGPKG_HAL_ARM_MXC91321_CHIP
466 if ((readl(CRM_MCU_BASE_ADDR + CLKCTL_PDR0) & (1 << 11)) != 0) {
467 CORE_PLL_SEL = TUR_PLL;
473 pll = pll_clock(CORE_PLL_SEL);
475 diag_printf("Wrong BRMM value in the CRM_AP, MPDR0 reg \n");
478 hclk = pll / (max_pdf + 1);
479 div = (pll * NORMALIZE_FACTOR) / hclk;
485 // new period = (2*MCU_period + 1*AHB_period)/3
486 // => new freq = (3*pll*hclk)/(2*hclk+pll)
487 // => new frq = (3*pll)/(2+pll/hclk). Also normalize it.
488 ret_val = (3* pll * NORMALIZE_FACTOR) /
489 ((2 * NORMALIZE_FACTOR) + ((pll * NORMALIZE_FACTOR) / hclk));
492 // new period = (1*MCU_period + 1*AHB_period)/2
493 // => new freq = (2*pll*hclk)/(hclk+pll)
494 // => new frq = (2*pll)/(1+pll/hclk). Also normalize it.
495 ret_val = (2* pll * NORMALIZE_FACTOR) /
496 ((1 * NORMALIZE_FACTOR) + ((pll * NORMALIZE_FACTOR) / hclk));
499 // new period = (1*MCU_period + 2*AHB_period)/3
500 // => new freq = (3*pll*hclk)/(hclk+2*pll)
501 // => new frq = (3*pll)/(1+(2*pll)/hclk). Also normalize it.
502 ret_val = (3* pll * NORMALIZE_FACTOR) /
503 ((1 * NORMALIZE_FACTOR) + ((2 * pll * NORMALIZE_FACTOR) / hclk));
513 pll = pll_clock(CORE_PLL_SEL);
514 ret_val = pll / (max_pdf + 1);
517 pll = pll_clock(CORE_PLL_SEL);
518 ret_val = pll / ((max_pdf + 1) * (ipg_pdf + 1));
521 pll = pll_clock(CORE_PLL_SEL);
522 ret_val = pll / ((max_pdf + 1) * (nfc_pdf + 1));
525 pll = pll_clock(USB_PLL);
526 ret_val = pll / (usb_pdf + 1);
529 diag_printf("%s(): This clock: %d not supported yet \n",
537 #ifdef CYGPKG_HAL_ARM_MXC91321_CHIP
538 static u32 csi_sdhc_clock_src(u32 clksrc)
544 val = pll_clock(USB_PLL);
547 val = pll_clock(MCU_PLL);
550 val = pll_clock(TUR_PLL);
561 * This function returns the peripheral clock value in Hz.
563 u32 get_peri_clock(enum peri_clocks clk)
565 volatile u32 mcr = readl(CRM_MCU_BASE_ADDR + CLKCTL_MCR);
566 volatile u32 mpdr0 = readl(CRM_MCU_BASE_ADDR + CLKCTL_PDR0);
567 volatile u32 mpdr1 = readl(CRM_MCU_BASE_ADDR + CLKCTL_PDR1);
568 u32 clk_sel, pre_pdf, pdf, ref_clk, ret_val = 0;
575 return get_main_clock(IPG_CLK);
578 pre_pdf = (mpdr1 >> 6) & 0x7;
579 pdf = (mpdr1 >> 1) & 0x1F;
580 clk_sel = mcr & (1 << 28);
581 ref_clk = (clk_sel != 0) ? pll_clock(USB_PLL) : pll_clock(MCU_PLL);
582 ret_val = ref_clk / ((pre_pdf + 1) * (pdf + 1));
585 pre_pdf = (mpdr1 >> 15) & 0x7;
586 pdf = (mpdr1 >> 10) & 0x1F;
587 clk_sel = mcr & (1 << 27);
588 ref_clk = (clk_sel != 0) ? pll_clock(USB_PLL) : pll_clock(MCU_PLL);
589 ret_val = ref_clk / ((pre_pdf + 1) * (pdf + 1));
592 #ifdef CYGPKG_HAL_ARM_MXC91321_CHIP
593 clk_sel = (mcr >> 25) & 0x3;
594 pdf = ((mpdr0 >> 23) & 0x1FF) + 1;
595 pdf = (2 * pdf) + (mpdr0 & (1 << 22)); //multiplied by 2
596 pdf *= (1 + (mpdr0 & (1 << 21)));
598 ret_val = (2 * csi_sdhc_clock_src(clk_sel)) / pdf;
602 pre_pdf = (mpdr1 >> 24) & 0x7;
603 pdf = (mpdr1 >> 19) & 0x1F;
604 clk_sel = mcr & (1 << 11);
605 ref_clk = (clk_sel != 0) ? pll_clock(USB_PLL) : pll_clock(MCU_PLL);
606 ret_val = ref_clk / ((pre_pdf + 1) * (pdf + 1));
610 ret_val = get_main_clock(IPG_CLK);
613 diag_printf("%s(): This clock: %d not supported yet \n",
622 "Select clock source for CKO1 (AKA CKO) (J10 on the EVB CPU daughter card)",
623 " The output is 1/8 of actual clock. Default is MCU_PLL\n\
624 <0> - display current cko selection\n\
632 <8> - MB_PAT_REF \n",
636 static u8* cko_name[] = {
648 #define CKO_MAX_INDEX (sizeof(cko_name) / sizeof(u8*))
649 #define CKO_DIV 3 // default divide by 8
650 #define CKOH_DIV 3 // default divide by 8
652 static void ckol(int argc,char *argv[])
654 u32 action = 0, cosr;
656 if (!scan_opts(argc, argv, 1, 0, 0, (void*) &action,
657 OPTION_ARG_TYPE_NUM, "action"))
660 if (action >= CKO_MAX_INDEX) {
661 diag_printf("%d is not supported\n\n", action);
665 cosr = readl(CRM_MCU_BASE_ADDR + CLKCTL_COSR);
668 cosr = (cosr & (~0x7F)) + (1 << 6) + (CKO_DIV << 3) + action - 1;
669 writel(cosr, CRM_MCU_BASE_ADDR + CLKCTL_COSR);
670 diag_printf("Set clko to ");
673 cosr = readl(CRM_MCU_BASE_ADDR + CLKCTL_COSR);
674 diag_printf("%s\n", cko_name[(cosr & 0x7) + 1]);
675 diag_printf("COSR register[0x%x] = 0x%x\n",
676 (CRM_MCU_BASE_ADDR + CLKCTL_COSR), cosr);
680 "Select clock source for CKO2 (J9 on the EVB CPU daughter card)",
681 " The default is 1/8 of IPG_CLK_ARM (core clock)\n\
682 <0> - display current cko selection\n\
692 <10> - MCU_AHB_CLK \n\
695 <13> - DSP_AHB_CLK \n\
696 <14> - IPG_CLK_ARM (Core) \n\
697 <15> - PAT_REF_CLK_SYNC \n\
698 <16> - WB_PAT_REF_CLK_SYNC \n\
699 <17> - TURBO_PLL (MXC91321 only)\n\
700 <18> - AFC_PLL (MXC91321 only) \n",
704 static u8* div_str[] = {
715 static u8* ckoh_name[] ={
730 "IPG_CLK_ARM (Core)",
732 "WB_PAT_REF_CLK_SYNC",
733 #ifdef CYGPKG_HAL_ARM_MXC91321_CHIP
739 #define CKOH_MAX_INDEX (sizeof(ckoh_name) / sizeof(u8*))
741 static void ckoh(int argc,char *argv[])
743 u32 action = 0, cosr, div = 0, i, j;
745 if (!scan_opts(argc, argv, 1, 0, 0, (void*) &action,
746 OPTION_ARG_TYPE_NUM, "action"))
749 if (action >= CKOH_MAX_INDEX) {
750 diag_printf("%d is not supported\n\n", action);
754 cosr = readl(CRM_MCU_BASE_ADDR + CLKCTL_COSR);
757 if (action == 1 || action == 3 || action == 4 || action == 5 || action == 14 || action == 17)
759 cosr = (cosr & (~0x0007FC00)) + (div << 10) + (1 << 13) +
760 ((action - 1) << 14);
761 writel(cosr, CRM_MCU_BASE_ADDR + CLKCTL_COSR);
762 diag_printf("Set clko to ");
765 cosr = readl(CRM_MCU_BASE_ADDR + CLKCTL_COSR);
766 i = (cosr >> 10) & 0x7;
767 j = (cosr >> 14) & 0x1F;
768 diag_printf("%s%s\n", div_str[i], ckoh_name[j + 1]);
769 diag_printf("COSR register[0x%x] = 0x%x\n",
770 (CRM_MCU_BASE_ADDR + CLKCTL_COSR), cosr);
775 * This command is added for some simple testing only. It turns on/off
776 * L2 cache regardless of L1 cache state. The side effect of this is
777 * when doing any flash operations such as "fis init", the L2
778 * will be turned back on along with L1 caches even though it is off
779 * by using this command.
787 void do_L2_caches(int argc, char *argv[])
793 if (strcasecmp(argv[1], "on") == 0) {
794 HAL_DISABLE_INTERRUPTS(oldints);
796 HAL_RESTORE_INTERRUPTS(oldints);
797 } else if (strcasecmp(argv[1], "off") == 0) {
798 HAL_DISABLE_INTERRUPTS(oldints);
799 HAL_CLEAN_INVALIDATE_L2();
801 HAL_RESTORE_INTERRUPTS(oldints);
803 diag_printf("Invalid L2 cache mode: %s\n", argv[1]);
806 HAL_L2CACHE_IS_ENABLED(L2cache_on);
807 diag_printf("L2 cache: %s\n", L2cache_on?"On":"Off");
810 #endif //L2CC_ENABLED
812 #define IIM_ERR_SHIFT 8
813 #define POLL_FUSE_PRGD (IIM_STAT_PRGD | (IIM_ERR_PRGE << IIM_ERR_SHIFT))
814 #define POLL_FUSE_SNSD (IIM_STAT_SNSD | (IIM_ERR_SNSE << IIM_ERR_SHIFT))
816 static void fuse_op_start(void)
818 /* Do not generate interrupt */
819 writel(0, IIM_BASE_ADDR + IIM_STATM_OFF);
820 // clear the status bits and error bits
821 writel(0x3, IIM_BASE_ADDR + IIM_STAT_OFF);
822 writel(0xFE, IIM_BASE_ADDR + IIM_ERR_OFF);
826 * The action should be either:
831 static int poll_fuse_op_done(int action)
836 if (action != POLL_FUSE_PRGD && action != POLL_FUSE_SNSD) {
837 diag_printf("%s(%d) invalid operation\n", __FUNCTION__, action);
841 /* Poll busy bit till it is NOT set */
842 while ((readl(IIM_BASE_ADDR + IIM_STAT_OFF) & IIM_STAT_BUSY) != 0 ) {
845 /* Test for successful write */
846 status = readl(IIM_BASE_ADDR + IIM_STAT_OFF);
847 error = readl(IIM_BASE_ADDR + IIM_ERR_OFF);
849 if ((status & action) != 0 && (error & (action >> IIM_ERR_SHIFT)) == 0) {
851 diag_printf("Even though the operation seems successful...\n");
852 diag_printf("There are some error(s) at addr=0x%x: 0x%x\n",
853 (IIM_BASE_ADDR + IIM_ERR_OFF), error);
857 diag_printf("%s(%d) failed\n", __FUNCTION__, action);
858 diag_printf("status address=0x%x, value=0x%x\n",
859 (IIM_BASE_ADDR + IIM_STAT_OFF), status);
860 diag_printf("There are some error(s) at addr=0x%x: 0x%x\n",
861 (IIM_BASE_ADDR + IIM_ERR_OFF), error);
865 static void sense_fuse(int bank, int row, int bit)
867 int addr, addr_l, addr_h, reg_addr;
871 addr = ((bank << 11) | (row << 3) | (bit & 0x7));
872 /* Set IIM Program Upper Address */
873 addr_h = (addr >> 8) & 0x000000FF;
874 /* Set IIM Program Lower Address */
875 addr_l = (addr & 0x000000FF);
877 #ifdef IIM_FUSE_DEBUG
878 diag_printf("%s: addr_h=0x%x, addr_l=0x%x\n",
879 __FUNCTION__, addr_h, addr_l);
881 writel(addr_h, IIM_BASE_ADDR + IIM_UA_OFF);
882 writel(addr_l, IIM_BASE_ADDR + IIM_LA_OFF);
884 writel(0x8, IIM_BASE_ADDR + IIM_FCTL_OFF);
885 if (poll_fuse_op_done(POLL_FUSE_SNSD) != 0) {
886 diag_printf("%s(bank: %d, row: %d, bit: %d failed\n",
887 __FUNCTION__, bank, row, bit);
889 reg_addr = IIM_BASE_ADDR + IIM_SDAT_OFF;
890 diag_printf("fuses at (bank:%d, row:%d) = 0x%x\n", bank, row, readl(reg_addr));
893 void do_fuse_read(int argc, char *argv[])
898 diag_printf("Useage: fuse_read <bank> <row>\n");
900 } else if (argc == 3) {
901 if (!parse_num(*(&argv[1]), (unsigned long *)&bank, &argv[1], " ")) {
902 diag_printf("Error: Invalid parameter\n");
905 if (!parse_num(*(&argv[2]), (unsigned long *)&row, &argv[2], " ")) {
906 diag_printf("Error: Invalid parameter\n");
910 diag_printf("Read fuse at bank:%d row:%d\n", bank, row);
911 sense_fuse(bank, row, 0);
914 diag_printf("Passing in wrong arguments: %d\n", argc);
915 diag_printf("Useage: fuse_read <bank> <row>\n");
919 /* Blow fuses based on the bank, row and bit positions (all 0-based)
921 static int fuse_blow(int bank,int row,int bit)
923 int addr, addr_l, addr_h, ret = -1;
927 /* Disable IIM Program Protect */
928 writel(0xAA, IIM_BASE_ADDR + IIM_PREG_P_OFF);
930 addr = ((bank << 11) | (row << 3) | (bit & 0x7));
931 /* Set IIM Program Upper Address */
932 addr_h = (addr >> 8) & 0x000000FF;
933 /* Set IIM Program Lower Address */
934 addr_l = (addr & 0x000000FF);
936 #ifdef IIM_FUSE_DEBUG
937 diag_printf("blowing addr_h=0x%x, addr_l=0x%x\n", addr_h, addr_l);
940 writel(addr_h, IIM_BASE_ADDR + IIM_UA_OFF);
941 writel(addr_l, IIM_BASE_ADDR + IIM_LA_OFF);
942 /* Start Programming */
943 writel(0x31, IIM_BASE_ADDR + IIM_FCTL_OFF);
944 if (poll_fuse_op_done(POLL_FUSE_PRGD) == 0) {
948 /* Enable IIM Program Protect */
949 writel(0x0, IIM_BASE_ADDR + IIM_PREG_P_OFF);
954 * This command is added for burning IIM fuses
956 RedBoot_cmd("fuse_read",
962 RedBoot_cmd("fuse_blow",
964 "<bank> <row> <value>",
968 #define INIT_STRING "12345678"
969 static char ready_to_blow[] = INIT_STRING;
971 void quick_itoa(u32 num, char *a)
974 for (i = 0; i <= 7; i++) {
975 j = (num >> (4 * i)) & 0xF;
976 k = (j < 10) ? '0' : ('a' - 0xa);
981 void do_fuse_blow(int argc, char *argv[])
983 int bank, row, value, i;
986 diag_printf("It is too dangeous for you to use this command.\n");
988 } else if (argc == 2) {
989 if (strcasecmp(argv[1], "nandboot") == 0) {
990 quick_itoa(readl(EPIT_BASE_ADDR + EPITCNR), ready_to_blow);
991 diag_printf("%s\n", ready_to_blow);
994 } else if (argc == 3) {
995 if (strcasecmp(argv[1], "nandboot") == 0 &&
996 strcasecmp(argv[2], ready_to_blow) == 0) {
997 #if defined(CYGPKG_HAL_ARM_MX21) || defined(CYGPKG_HAL_ARM_MX27) || defined(CYGPKG_HAL_ARM_MX31)
998 diag_printf("No need to blow any fuses for NAND boot on this platform\n\n");
1000 diag_printf("Ready to burn NAND boot fuses\n");
1001 if (fuse_blow(0, 16, 1) != 0 || fuse_blow(0, 16, 7) != 0) {
1002 diag_printf("NAND BOOT fuse blown failed miserably ...\n");
1004 diag_printf("NAND BOOT fuse blown successfully ...\n");
1007 diag_printf("Not ready: %s, %s\n", argv[1], argv[2]);
1010 } else if (argc == 4) {
1011 if (!parse_num(*(&argv[1]), (unsigned long *)&bank, &argv[1], " ")) {
1012 diag_printf("Error: Invalid parameter\n");
1015 if (!parse_num(*(&argv[2]), (unsigned long *)&row, &argv[2], " ")) {
1016 diag_printf("Error: Invalid parameter\n");
1019 if (!parse_num(*(&argv[3]), (unsigned long *)&value, &argv[3], " ")) {
1020 diag_printf("Error: Invalid parameter\n");
1024 diag_printf("Blowing fuse at bank:%d row:%d value:%d\n",
1026 for (i = 0; i < 8; i++) {
1027 if (((value >> i) & 0x1) == 0) {
1030 if (fuse_blow(bank, row, i) != 0) {
1031 diag_printf("fuse_blow(bank: %d, row: %d, bit: %d failed\n",
1034 diag_printf("fuse_blow(bank: %d, row: %d, bit: %d successful\n",
1038 sense_fuse(bank, row, 0);
1041 diag_printf("Passing in wrong arguments: %d\n", argc);
1043 /* Reset to default string */
1044 strcpy(ready_to_blow, INIT_STRING);;
1047 /* precondition: m>0 and n>0. Let g=gcd(m,n). */
1048 int gcd(int m, int n)
1052 if(n > m) {t = m; m = n; n = t;} /* swap */