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
55 #define PLL_MFI_MIN 6 // See TLSbo80174
56 #define PLL_MFD_MAX 1024 //actual mfd+1
57 #define PLL_MFN_MAX 1022
58 #define PLL_MFN_MAX_2 510
61 #define AHB_DIV_MAX 16
66 #define PLL_FREQ_MAX (2 * PLL_REF_CLK * PLL_MFI_MAX)
67 #define PLL_FREQ_MIN ((2 * PLL_REF_CLK * PLL_MFI_MIN) / PLL_PD_MAX)
68 #define AHB_CLK_MAX 133333333
69 #define IPG_CLK_MAX (AHB_CLK_MAX / 2)
70 #define NFC_CLK_MAX 33333333
72 #define ERR_WRONG_CLK -1
76 #define ERR_NO_PRESC -5
78 u32 pll_clock(enum plls pll);
79 u32 get_main_clock(enum main_clocks clk);
80 u32 get_peri_clock(enum peri_clocks clk);
82 static u32 pll_mfd_fixed;
84 static void clock_setup(int argc, char *argv[]);
85 static void clko(int argc, char *argv[]);
86 extern unsigned int g_clock_src;
87 extern unsigned int system_rev;
90 #define MXC_PERCLK_NUM 4
92 #ifdef CYGOPT_MX27_WORKAROUND_ENGcm11563
93 #define avoid_arm_src 1
95 #define avoid_arm_src 0
99 "Setup/Display clock (max AHB=133MHz, max IPG=66.5MHz)\nSyntax:",
100 "[<core clock in MHz> [:<AHB-to-core divider>[:<IPG-to-AHB divider>]]]\n\n"
101 "If a divider is zero or no divider is specified, the optimum divider values\n"
102 "will be chosen. Examples:\n"
103 " [clock] -> Show various clocks\n"
104 " [clock 266] -> Core=266 AHB=133 IPG=66.5\n"
105 " [clock 350] -> Core=350 AHB=117 IPG=58.5\n"
106 " [clock 266:4] -> Core=266 AHB=66.5(Core/4) IPG=66.5\n"
107 " [clock 266:4:2] -> Core=266 AHB=66.5(Core/4) 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, int *p_pd,
127 int *p_mfi, int *p_mfn, int *p_mfd)
130 u64 n_target = target, n_ref = ref;
132 if (g_clock_src == FREQ_26MHZ) {
133 pll_mfd_fixed = 26 * 16;
134 } else if (g_clock_src == FREQ_27MHZ) {
135 pll_mfd_fixed = 27 * 16;
140 // Make sure targeted freq is in the valid range. Otherwise the
141 // following calculation might be wrong!!!
142 if (target < PLL_FREQ_MIN || target > PLL_FREQ_MAX) {
143 return ERR_WRONG_CLK;
145 // Use n_target and n_ref to avoid overflow
146 for (pd = 1; pd <= PLL_PD_MAX; pd++) {
147 mfi = (n_target * pd) / (2 * n_ref);
148 if (mfi > PLL_MFI_MAX) {
150 } else if (mfi < PLL_MFI_MIN) {
155 // Now got pd and mfi already
156 mfn = (((n_target * pd) / 2 - n_ref * mfi) * pll_mfd_fixed) / n_ref;
157 // Check mfn within limit and mfn < denominator
158 if (sys_ver == SOC_SILICONID_Rev1_0) {
159 if (mfn < 0 || mfn > PLL_MFN_MAX || mfn >= pll_mfd_fixed) {
163 if (mfn < -PLL_MFN_MAX_2 || mfn > PLL_MFN_MAX_2 || mfn >= pll_mfd_fixed) {
168 if (pd > PLL_PD_MAX) {
174 *p_mfd = pll_mfd_fixed;
178 static u32 per_clk_old[MXC_PERCLK_NUM];
181 * This function assumes the expected core clock has to be changed by
182 * modifying the PLL. This is NOT true always but for most of the times,
183 * it is. So it assumes the PLL output freq is the same as the expected
184 * core clock (presc=1) unless the core clock is less than PLL_FREQ_MIN.
185 * In the latter case, it will try to increase the presc value until
186 * (presc*core_clk) is greater than PLL_FREQ_MIN. It then makes call to
187 * calc_pll_params() and obtains the values of PD, MFI,MFN, MFD based
188 * on the targeted PLL and reference input clock to the PLL. Lastly,
189 * it sets the register based on these values along with the dividers.
190 * Note 1) There is no value checking for the passed-in divider values
191 * so the caller has to make sure those values are sensible.
192 * 2) Also adjust the NFC divider such that the NFC clock doesn't
193 * exceed NFC_CLK_MAX (which is 33MHz now).
194 * 3) Added feature to maintain the perclock before and after the call.
195 * !!!! 4) This function can't have printf in it since the serial i/f is
198 * @param ref pll input reference clock (32KHz or 26MHz)
199 * @param core_clk core clock in Hz
200 * @param ahb_div ahb divider to divide the core clock to get ahb clock
201 * (ahb_div - 1) needs to be set in the register
202 * @param ipg_div ipg divider to divide the ahb clock to get ipg clock
203 * (ipg_div - 1) needs to be set in the register
204 # @return 0 if successful; non-zero otherwise
206 #define CMD_CLOCK_DEBUG
207 int configure_clock(u32 ref, u32 core_clk, u32 ahb_div, u32 ipg_div)
210 int pd, mfi, mfn, mfd;
212 u32 pcdr0, nfc_div, hdiv, nfc_div_factor;
213 u32 per_div[MXC_PERCLK_NUM];
214 int ret, i, arm_src = 0;
216 per_clk_old[0] = get_peri_clock(PER_CLK1);
217 per_clk_old[1] = get_peri_clock(PER_CLK2);
218 per_clk_old[2] = get_peri_clock(PER_CLK3);
219 per_clk_old[3] = get_peri_clock(PER_CLK4);
220 diag_printf("per1=%9u\n", per_clk_old[0]);
221 diag_printf("per2=%9u\n", per_clk_old[1]);
222 diag_printf("per3=%9u\n", per_clk_old[2]);
223 diag_printf("per4=%9u\n", per_clk_old[3]);
224 // assume pll default to core clock first
225 if (sys_ver == SOC_SILICONID_Rev1_0) {
229 if (!avoid_arm_src && core_clk > 266 * SZ_DEC_1M) {
233 pll = core_clk * 3 / 2;
235 nfc_div_factor = ahb_div;
238 // when core_clk >= PLL_FREQ_MIN, the presc can be 1.
239 // Otherwise, need to calculate presc value below and adjust the targeted pll
240 if (pll < PLL_FREQ_MIN) {
243 if (sys_ver == SOC_SILICONID_Rev1_0) {
244 presc_max = PRESC_MAX;
246 presc_max = ARM_DIV_MAX;
249 for (presc = 1; presc <= presc_max; presc++) {
250 if (pll * presc > PLL_FREQ_MIN) {
254 if (presc == presc_max + 1) {
255 diag_printf("can't make presc=%d\n", presc);
258 if (sys_ver == SOC_SILICONID_Rev1_0) {
259 pll = core_clk * presc;
261 pll = 3 * core_clk * presc / 2;
264 // pll is now the targeted pll output. Use it along with ref input clock
265 // to get pd, mfi, mfn, mfd
266 if ((ret = calc_pll_params(ref, pll, &pd, &mfi, &mfn, &mfd)) != 0) {
267 #ifdef CMD_CLOCK_DEBUG
268 diag_printf("can't find pll parameters: %d\n", ret);
272 #ifdef CMD_CLOCK_DEBUG
273 diag_printf("ref=%d, pll=%d, pd=%d, mfi=%d,mfn=%d, mfd=%d\n",
274 ref, pll, pd, mfi, mfn, mfd);
277 // blindly increase divider first to avoid too fast ahbclk and ipgclk
278 // in case the core clock increases too much
279 cscr = readl(SOC_CRM_CSCR);
280 if (sys_ver == SOC_SILICONID_Rev1_0) {
281 hdiv = (pll + AHB_CLK_MAX - 1) / AHB_CLK_MAX;
282 cscr = (cscr & ~0x0000FF00) | ((hdiv - 1) << 9) | (1 << 8);
284 if (core_clk > 266 * SZ_DEC_1M) {
285 hdiv = (pll + AHB_CLK_MAX - 1) / AHB_CLK_MAX;
287 hdiv = (2 * pll + 3 * AHB_CLK_MAX - 1) / (3 * AHB_CLK_MAX);
289 cscr = (cscr & ~0x0000FF00) | ((hdiv - 1) << 8);
291 writel(cscr, SOC_CRM_CSCR);
293 // update PLL register
294 if (!((mfd < 10 * mfn) && (10 * mfn < 9 * mfd)))
295 writel(1 << 6, SOC_CRM_MPCTL1);
297 mpctl0 = readl(SOC_CRM_MPCTL0);
298 mpctl0 = (mpctl0 & 0xC000C000) |
304 writel(mpctl0, SOC_CRM_MPCTL0);
307 writel((cscr | (1 << 18)), SOC_CRM_CSCR);
308 // check the LF bit to insure lock
309 while ((readl(SOC_CRM_MPCTL1) & (1 << 15)) == 0);
310 // have to add some delay for new values to take effect
311 for (i = 0; i < 100000; i++);
313 // PLL locked already so use the new divider values
314 cscr = readl(SOC_CRM_CSCR);
317 if (sys_ver == SOC_SILICONID_Rev1_0) {
318 cscr |= ((presc - 1) << 13) | ((ahb_div - 1) << 9) | ((ipg_div - 1) << 8);
320 cscr |= (arm_src << 15) | ((presc - 1) << 12) | ((ahb_div - 1) << 8);
322 writel(cscr, SOC_CRM_CSCR);
324 // Make sure optimal NFC clock but less than NFC_CLK_MAX
325 for (nfc_div = 1; nfc_div <= 16; nfc_div++) {
326 if ((core_clk / (nfc_div_factor * nfc_div)) <= NFC_CLK_MAX) {
330 pcdr0 = readl(SOC_CRM_PCDR0);
331 if (sys_ver == SOC_SILICONID_Rev1_0) {
332 writel(((pcdr0 & 0xFFFF0FFF) | ((nfc_div - 1) << 12)),
335 writel(((pcdr0 & 0xFFFFF3CF) | ((nfc_div - 1) << 6)),
339 if (sys_ver == SOC_SILICONID_Rev1_0) {
340 pll = pll_clock(MCU_PLL) + 500000;
342 if (core_clk > (266 * SZ_DEC_1M)) {
343 pll = pll_clock(MCU_PLL) + 500000;
345 pll = 2 * pll_clock(MCU_PLL) / 3 + 500000;
348 for (i = 0; i < MXC_PERCLK_NUM; i++) {
349 per_div[i] = (pll / per_clk_old[i]) - 1;
351 writel((per_div[3] << 24) | (per_div[2] << 16) | (per_div[1] << 8) |
352 (per_div[0]), SOC_CRM_PCDR1);
357 static void clock_setup(int argc, char *argv[])
359 u32 i, core_clk, ipg_div, data[3], ahb_div, ahb_clk, ahb_clk_in, ipg_clk;
360 u32 presc_max, ahb_div_max, pll;
366 if (g_clock_src == FREQ_27MHZ) {
367 diag_printf("Error: clock setup is not supported for 27MHz source\n");
370 for (i = 0; i < 3; i++) {
371 if (!parse_num(argv[1], &temp, &argv[1], ":")) {
372 diag_printf("Error: Invalid parameter\n");
378 core_clk = data[0] * SZ_DEC_1M;
379 ahb_div = data[1]; // actual register field + 1
380 ipg_div = data[2]; // actual register field + 1
382 if (sys_ver == SOC_SILICONID_Rev1_0) {
383 presc_max = PRESC_MAX;
384 ahb_div_max = AHB_DIV_MAX;
386 ahb_clk_in = core_clk;
388 presc_max = ARM_DIV_MAX;
389 ahb_div_max = AHB_DIV_MAX / ARM_DIV_MAX;
390 if (core_clk > (266 * SZ_DEC_1M)) {
392 ahb_clk_in = core_clk * 2 / 3;
394 pll = 3 * core_clk / 2;
395 ahb_clk_in = core_clk;
400 if (pll < (PLL_FREQ_MIN / presc_max) || pll > PLL_FREQ_MAX) {
401 diag_printf("Targeted core clock should be within [%d - %d]\n",
402 PLL_FREQ_MIN / presc_max, PLL_FREQ_MAX);
406 // find the ahb divider
407 if (ahb_div > ahb_div_max) {
408 diag_printf("Invalid AHB divider: %d. Maximum value is %d\n",
409 ahb_div, ahb_div_max);
413 // no AHBCLK divider specified
414 for (ahb_div = 1; ; ahb_div++) {
415 if ((ahb_clk_in / ahb_div) <= AHB_CLK_MAX) {
420 if (ahb_div > ahb_div_max || (ahb_clk_in / ahb_div) > AHB_CLK_MAX) {
421 diag_printf("Can't make AHB=%d since max=%d\n",
422 core_clk / ahb_div, AHB_CLK_MAX);
426 // find the ipg divider
427 ahb_clk = ahb_clk_in / ahb_div;
428 if (ipg_div > IPG_DIV_MAX) {
429 diag_printf("Invalid IPG divider: %d. Maximum value is %d\n",
430 ipg_div, IPG_DIV_MAX);
434 ipg_div++; // At least =1
435 if (ahb_clk > IPG_CLK_MAX)
436 ipg_div++; // Make it =2
438 if (ipg_div > IPG_DIV_MAX || (ahb_clk / ipg_div) > IPG_CLK_MAX) {
439 diag_printf("Can't make IPG=%d since max=%d\n",
440 (ahb_clk / ipg_div), IPG_CLK_MAX);
443 ipg_clk = ahb_clk / ipg_div;
445 diag_printf("Trying to set core=%d ahb=%d ipg=%d...\n",
446 core_clk, ahb_clk, ipg_clk);
448 // stop the serial to be ready to adjust the clock
449 hal_delay_us(100000);
450 cyg_hal_plf_serial_stop();
452 ret = configure_clock(PLL_REF_CLK, core_clk, ahb_div, ipg_div);
453 // restart the serial driver
454 cyg_hal_plf_serial_init();
455 hal_delay_us(100000);
458 diag_printf("Failed to setup clock: %d\n", ret);
462 // check for new per clock settings and warn user if there is a change.
463 if (per_clk_old[0] != get_peri_clock(PER_CLK1)) {
464 diag_printf("per_clk1 changed; old clock was: %u\n", per_clk_old[0]);
466 if (per_clk_old[1] != get_peri_clock(PER_CLK2)) {
467 diag_printf("per_clk2 changed; old clock was: %u\n", per_clk_old[1]);
469 if (per_clk_old[2] != get_peri_clock(PER_CLK3)) {
470 diag_printf("per_clk3 changed; old clock was: %u\n", per_clk_old[2]);
472 if (per_clk_old[3] != get_peri_clock(PER_CLK4)) {
473 diag_printf("per_clk4 changed; old clock was: %u\n", per_clk_old[3]);
476 diag_printf("\n<<<New clock setting>>>\n");
478 // Now printing clocks
480 diag_printf("\nMPLL\t\tSPLL\n");
481 diag_printf("=========================\n");
482 diag_printf("%-16d%-16d\n\n", pll_clock(MCU_PLL), pll_clock(SER_PLL));
483 diag_printf("CPU\t\tAHB\t\tIPG\t\tNFC\t\tUSB\n");
484 diag_printf("========================================================================\n");
485 diag_printf("%-16d%-16d%-16d%-16d%-16d\n\n",
486 get_main_clock(CPU_CLK),
487 get_main_clock(AHB_CLK),
488 get_main_clock(IPG_CLK),
489 get_main_clock(NFC_CLK),
490 get_main_clock(USB_CLK));
492 diag_printf("PER1\t\tPER2\t\tPER3\t\tPER4\n");
493 diag_printf("===========================================");
494 diag_printf("=============\n");
496 diag_printf("%-16d%-16d%-16d%-16d\n\n",
497 get_peri_clock(PER_CLK1),
498 get_peri_clock(PER_CLK2),
499 get_peri_clock(PER_CLK3),
500 get_peri_clock(PER_CLK4));
502 diag_printf("H264\t\tMSHC\t\tSSI1\t\tSSI2\n");
503 diag_printf("========================================================\n");
504 diag_printf("%-16d%-16d%-16d%-16d\n\n",
505 get_peri_clock(H264_BAUD),
506 get_peri_clock(MSHC_BAUD),
507 get_peri_clock(SSI1_BAUD),
508 get_peri_clock(SSI2_BAUD));
509 diag_printf("PERCLK: 1-<UART|GPT|PWM> 2-<SDHC|CSPI> 3-<LCDC> 4-<CSI>\n");
513 * This function returns the PLL output value in Hz based on pll.
515 u32 pll_clock(enum plls pll)
517 int mfi, mfn, mfd, pdf;
519 u32 reg = readl(pll);
522 if ((pll == SER_PLL) && (sys_ver == SOC_SILICONID_Rev2_0)) {
525 pdf = (reg >> 26) & 0xF;
526 mfd = (reg >> 16) & 0x3FF;
527 mfi = (reg >> 10) & 0xF;
535 ref_clk = g_clock_src;
537 pll_out = (2 * ref_clk * mfi + ((2 * ref_clk * mfn) / (mfd + 1))) /
544 * This function returns the main clock value in Hz.
546 u32 get_main_clock(enum main_clocks clk)
548 u32 presc, ahb_div, ipg_pdf, nfc_div;
549 u32 ret_val = 0, usb_div;
550 u32 cscr = readl(SOC_CRM_CSCR);
551 u32 pcdr0 = readl(SOC_CRM_PCDR0);
553 if (sys_ver == SOC_SILICONID_Rev1_0) {
554 presc = ((cscr >> CRM_CSCR_PRESC_OFFSET) & 0x7) + 1;
556 presc = ((cscr >> CRM_CSCR_ARM_OFFSET) & 0x3) + 1;
561 if ((sys_ver == SOC_SILICONID_Rev1_0) || (cscr & CRM_CSCR_ARM_SRC)) {
562 ret_val = pll_clock(MCU_PLL) / presc;
564 ret_val = 2 * pll_clock(MCU_PLL) / (3 * presc);
568 if (sys_ver == SOC_SILICONID_Rev1_0) {
569 ahb_div = ((cscr >> CRM_CSCR_BCLKDIV_OFFSET) & 0xF) + 1;
570 ret_val = pll_clock(MCU_PLL) / (presc * ahb_div);
572 ahb_div = ((cscr >> CRM_CSCR_AHB_OFFSET) & 0x3) + 1;
573 ret_val = 2 * pll_clock(MCU_PLL) / (3 * ahb_div);
577 if (sys_ver == SOC_SILICONID_Rev1_0) {
578 ahb_div = ((cscr >> CRM_CSCR_BCLKDIV_OFFSET) & 0xF) + 1;
579 ipg_pdf = ((cscr >> CRM_CSCR_IPDIV_OFFSET) & 0x1) + 1;
580 ret_val = pll_clock(MCU_PLL) / (presc * ahb_div * ipg_pdf);
582 ahb_div = ((cscr >> CRM_CSCR_AHB_OFFSET) & 0x3) + 1;
583 ret_val = pll_clock(MCU_PLL) / (3 * ahb_div);
587 if (sys_ver == SOC_SILICONID_Rev1_0) {
588 nfc_div = ((pcdr0 >> 12) & 0xF) + 1;
590 ret_val = pll_clock(MCU_PLL) / (presc * nfc_div);
592 nfc_div = ((pcdr0 >> 6) & 0xF) + 1;
593 ahb_div = ((cscr >> CRM_CSCR_AHB_OFFSET) & 0x3) + 1;
594 ret_val = 2*pll_clock(MCU_PLL) / (3 * ahb_div * nfc_div);
598 usb_div = ((cscr >> CRM_CSCR_USB_DIV_OFFSET) & 0x7) + 1;
599 ret_val = pll_clock(SER_PLL) / usb_div;
602 diag_printf("Unknown clock: %d\n", clk);
609 * This function returns the peripheral clock value in Hz.
611 u32 get_peri_clock(enum peri_clocks clk)
613 u32 ret_val = 0, div;
614 u32 pcdr0 = readl(SOC_CRM_PCDR0);
615 u32 pcdr1 = readl(SOC_CRM_PCDR1);
616 u32 cscr = readl(SOC_CRM_CSCR);
620 div = (pcdr1 & 0x3F) + 1;
621 if (sys_ver == SOC_SILICONID_Rev1_0) {
622 ret_val = pll_clock(MCU_PLL) / div;
624 ret_val = 2 * pll_clock(MCU_PLL) / (3 * div);
630 div = ((pcdr1 >> 8) & 0x3F) + 1;
631 if (sys_ver == SOC_SILICONID_Rev1_0) {
632 ret_val = pll_clock(MCU_PLL) / div;
634 ret_val = 2 * pll_clock(MCU_PLL) / (3 * div);
638 div = ((pcdr1 >> 16) & 0x3F) + 1;
639 if (sys_ver == SOC_SILICONID_Rev1_0) {
640 ret_val = pll_clock(MCU_PLL) / div;
642 ret_val = 2 * pll_clock(MCU_PLL) / (3 * div);
646 div = ((pcdr1 >> 24) & 0x3F) + 1;
647 if (sys_ver == SOC_SILICONID_Rev1_0) {
648 ret_val = pll_clock(MCU_PLL) / div;
650 ret_val = 2 * pll_clock(MCU_PLL) / (3 * div);
654 div = (pcdr0 >> 16) & 0x3F;
655 if (sys_ver == SOC_SILICONID_Rev1_0) {
662 if ((cscr & (1 << 22)) != 0) {
663 // This takes care of 0.5*SSIDIV[0] by x2
664 if (sys_ver == SOC_SILICONID_Rev1_0) {
665 ret_val = (2 * pll_clock(MCU_PLL)) / div;
667 ret_val = (4 * pll_clock(MCU_PLL)) / (3 * div);
670 ret_val = (2 * pll_clock(SER_PLL)) / div;
674 div = (pcdr0 >> 26) & 0x3F;
675 if (sys_ver == SOC_SILICONID_Rev1_0) {
682 if ((cscr & (1 << 23)) != 0) {
683 if (sys_ver == SOC_SILICONID_Rev1_0) {
684 ret_val = (2 * pll_clock(MCU_PLL)) / div;
686 ret_val = (4 * pll_clock(MCU_PLL)) / (3 * div);
689 ret_val = (2 * pll_clock(SER_PLL)) / div;
693 if (sys_ver == SOC_SILICONID_Rev1_0) {
694 div = (pcdr0 >> 8) & 0xF;
699 div = (pcdr0 >> 10) & 0x3F;
702 if ((cscr & (1 << 21)) != 0) {
703 if (sys_ver == SOC_SILICONID_Rev1_0) {
704 ret_val = (2 * pll_clock(MCU_PLL)) / div;
706 ret_val = (4 * pll_clock(MCU_PLL)) / (3 * div);
709 ret_val = (2 * pll_clock(SER_PLL)) / div;
713 if ((cscr & (1 << 20)) != 0) {
714 if (sys_ver == SOC_SILICONID_Rev1_0) {
715 div = (pcdr0 & 0x1F) + 1;
716 ret_val = pll_clock(MCU_PLL) / div;
718 div = (pcdr0 & 0x3F) + 1;
719 ret_val = 2 * pll_clock(MCU_PLL) / (3 * div);
722 div = (pcdr0 & 0x1F) + 1;
723 ret_val = (2 * pll_clock(SER_PLL)) / div;
727 diag_printf("%s(): This clock: %d not supported yet\n",
736 "Select clock source for CLKO (TP1 on EVB or S3 Pin 1)",
737 " The output clock is the actual clock source freq divided by 8. Default is FCLK\n"
738 " Note that the module clock will be turned on for reading!\n"
739 " <0> - display current clko selection\n"
742 " <3> - CLK26M (may see nothing if 26MHz Crystal is not connected)\n"
743 " <4> - MPLL Reference CLK\n"
744 " <5> - SPLL Reference CLK\n"
749 " <10> - IPG_CLK (PERCLK)\n"
754 " <15> - SSI 1 Baud\n"
755 " <16> - SSI 2 Baud\n"
757 " <18> - MSHC Baud\n"
758 " <19> - H264 Baud\n"
759 " <20> - CLK60M Always\n"
760 " <21> - CLK32K Always\n"
766 static u8* clko_name[] = {
770 "CLK26M (may see nothing if 26MHz Crystal is not connected)",
771 "MPLL Reference CLK",
772 "SPLL Reference CLK",
793 #define CLKO_MAX_INDEX (sizeof(clko_name) / sizeof(u8*))
795 static void clko(int argc,char *argv[])
797 u32 action = 0, ccsr;
799 if (!scan_opts(argc, argv, 1, 0, 0, &action,
800 OPTION_ARG_TYPE_NUM, "action"))
803 if (action >= CLKO_MAX_INDEX) {
804 diag_printf("%d is not supported\n", action);
808 ccsr = readl(SOC_CRM_CCSR);
811 ccsr = (ccsr & (~0x1F)) + action - 1;
812 writel(ccsr, SOC_CRM_CCSR);
813 diag_printf("Set clko to ");
816 ccsr = readl(SOC_CRM_CCSR);
817 diag_printf("%s\n", clko_name[(ccsr & 0x1F) + 1]);
818 diag_printf("CCSR register[0x%08lx] = 0x%08x\n", SOC_CRM_CCSR, ccsr);
821 extern int flash_program(void *_addr, void *_data, int len, void **err_addr);
822 extern int flash_erase(void *addr, int len, void **err_addr);
824 void auto_flash_start(void)
828 int nor_update = 1; //todo: need to support NAND
829 u32 src = readl(SERIAL_DOWNLOAD_SRC_REG);
830 u32 dst = readl(SERIAL_DOWNLOAD_TGT_REG);
831 u32 sz = readl(SERIAL_DOWNLOAD_SZ_REG);
833 if (readl(SERIAL_DOWNLOAD_MAGIC_REG) != SERIAL_DOWNLOAD_MAGIC) {
838 // Erase area to be programmed
839 if ((stat = flash_erase((void *)dst, sz, &err_addr)) != 0) {
840 diag_printf("BEADDEAD\n");
843 diag_printf("BEADBEEF\n");
845 if ((stat = flash_program((void *)dst, (void *)src, sz,
847 diag_printf("BEADFEEF\n");
850 diag_printf("BEADCEEF\n");
853 RedBoot_init(auto_flash_start, RedBoot_INIT_LAST);
855 #define IIM_ERR_SHIFT 8
856 #define POLL_FUSE_PRGD (IIM_STAT_PRGD | (IIM_ERR_PRGE << IIM_ERR_SHIFT))
857 #define POLL_FUSE_SNSD (IIM_STAT_SNSD | (IIM_ERR_SNSE << IIM_ERR_SHIFT))
859 static void fuse_op_start(void)
861 /* Do not generate interrupt */
862 writel(0, IIM_BASE_ADDR + IIM_STATM_OFF);
863 // clear the status bits and error bits
864 writel(0x3, IIM_BASE_ADDR + IIM_STAT_OFF);
865 writel(0xFE, IIM_BASE_ADDR + IIM_ERR_OFF);
869 * The action should be either:
874 static int poll_fuse_op_done(int action)
878 if (action != POLL_FUSE_PRGD && action != POLL_FUSE_SNSD) {
879 diag_printf("%s(%d) invalid operation\n", __FUNCTION__, action);
883 /* Poll busy bit till it is NOT set */
884 while ((readl(IIM_BASE_ADDR + IIM_STAT_OFF) & IIM_STAT_BUSY) != 0 ) {
887 /* Test for successful write */
888 status = readl(IIM_BASE_ADDR + IIM_STAT_OFF);
889 error = readl(IIM_BASE_ADDR + IIM_ERR_OFF);
891 if ((status & action) != 0 && (error & (action >> IIM_ERR_SHIFT)) == 0) {
893 diag_printf("Even though the operation seems successful...\n");
894 diag_printf("There are some error(s) at addr=0x%08lx: 0x%08x\n",
895 (IIM_BASE_ADDR + IIM_ERR_OFF), error);
899 diag_printf("%s(%d) failed\n", __FUNCTION__, action);
900 diag_printf("status address=0x%08lx, value=0x%08x\n",
901 (IIM_BASE_ADDR + IIM_STAT_OFF), status);
902 diag_printf("There are some error(s) at addr=0x%08lx: 0x%08x\n",
903 (IIM_BASE_ADDR + IIM_ERR_OFF), error);
907 static void sense_fuse(int bank, int row, int bit)
910 int addr, addr_l, addr_h, reg_addr;
914 addr = ((bank << 11) | (row << 3) | (bit & 0x7));
915 /* Set IIM Program Upper Address */
916 addr_h = (addr >> 8) & 0x000000FF;
917 /* Set IIM Program Lower Address */
918 addr_l = (addr & 0x000000FF);
920 #ifdef IIM_FUSE_DEBUG
921 diag_printf("%s: addr_h=0x%02x, addr_l=0x%02x\n",
922 __FUNCTION__, addr_h, addr_l);
924 writel(addr_h, IIM_BASE_ADDR + IIM_UA_OFF);
925 writel(addr_l, IIM_BASE_ADDR + IIM_LA_OFF);
927 writel(0x8, IIM_BASE_ADDR + IIM_FCTL_OFF);
928 if ((ret = poll_fuse_op_done(POLL_FUSE_SNSD)) != 0) {
929 diag_printf("%s(bank: %d, row: %d, bit: %d failed\n",
930 __FUNCTION__, bank, row, bit);
932 reg_addr = IIM_BASE_ADDR + IIM_SDAT_OFF;
934 diag_printf("fuses at (bank:%d, row:%d) = 0x%02x\n", bank, row, readl(reg_addr));
937 void do_fuse_read(int argc, char *argv[])
939 unsigned long bank, row;
942 diag_printf("Usage: fuse_read <bank> <row>\n");
944 } else if (argc == 3) {
945 if (!parse_num(argv[1], &bank, &argv[1], " ")) {
946 diag_printf("Error: Invalid parameter\n");
949 if (!parse_num(argv[2], &row, &argv[2], " ")) {
950 diag_printf("Error: Invalid parameter\n");
954 diag_printf("Read fuse at bank:%ld row:%ld\n", bank, row);
955 sense_fuse(bank, row, 0);
958 diag_printf("Passing in wrong arguments: %d\n", argc);
959 diag_printf("Usage: fuse_read <bank> <row>\n");
963 /* Blow fuses based on the bank, row and bit positions (all 0-based)
965 int fuse_blow(int bank, int row, int bit)
967 int addr, addr_l, addr_h, ret = -1;
971 /* Disable IIM Program Protect */
972 writel(0xAA, IIM_BASE_ADDR + IIM_PREG_P_OFF);
974 addr = ((bank << 11) | (row << 3) | (bit & 0x7));
975 /* Set IIM Program Upper Address */
976 addr_h = (addr >> 8) & 0x000000FF;
977 /* Set IIM Program Lower Address */
978 addr_l = (addr & 0x000000FF);
980 diag_printf("blowing fuse bank %d row %d bit %d\n", bank, row, bit & 7);
981 #ifdef IIM_FUSE_DEBUG
982 diag_printf("blowing addr_h=0x%02x, addr_l=0x%02x\n", addr_h, addr_l);
985 writel(addr_h, IIM_BASE_ADDR + IIM_UA_OFF);
986 writel(addr_l, IIM_BASE_ADDR + IIM_LA_OFF);
987 /* Start Programming */
988 writel(0x71, IIM_BASE_ADDR + IIM_FCTL_OFF);
989 if (poll_fuse_op_done(POLL_FUSE_PRGD) == 0) {
993 /* Enable IIM Program Protect */
994 writel(0x0, IIM_BASE_ADDR + IIM_PREG_P_OFF);
999 * This command is added for burning IIM fuses
1001 RedBoot_cmd("fuse_read",
1007 RedBoot_cmd("fuse_blow",
1009 "<bank> <row> <value>",
1013 #define INIT_STRING "12345678"
1014 static char ready_to_blow[] = INIT_STRING;
1016 void do_fuse_blow(int argc, char *argv[])
1018 unsigned long bank, row, value;
1022 diag_printf("It is too dangeous for you to use this command.\n");
1024 } else if (argc == 2) {
1025 if (strcasecmp(argv[1], "nandboot") == 0) {
1026 diag_printf("%s\n", "fuse blown not needed");
1029 } else if (argc == 3) {
1030 if (strcasecmp(argv[1], "nandboot") == 0) {
1031 #if defined(CYGPKG_HAL_ARM_MXC91131) || defined(CYGPKG_HAL_ARM_MX21) || defined(CYGPKG_HAL_ARM_MX27) || defined(CYGPKG_HAL_ARM_MX31)
1032 diag_printf("No need to blow any fuses for NAND boot on this platform\n");
1034 diag_printf("Ready to burn NAND boot fuses\n");
1035 if (fuse_blow(0, 16, 1) != 0 || fuse_blow(0, 16, 7) != 0) {
1036 diag_printf("NAND BOOT fuse blown failed miserably ...\n");
1038 diag_printf("NAND BOOT fuse blown successfully ...\n");
1041 diag_printf("Not ready: %s, %s\n", argv[1], argv[2]);
1044 } else if (argc == 4) {
1045 if (!parse_num(argv[1], &bank, &argv[1], " ")) {
1046 diag_printf("Error: Invalid fuse bank\n");
1049 if (!parse_num(argv[2], &row, &argv[2], " ")) {
1050 diag_printf("Error: Invalid fuse row\n");
1053 if (!parse_num(argv[3], &value, &argv[3], " ")) {
1054 diag_printf("Error: Invalid value\n");
1058 if (!verify_action("Confirm to blow fuse at bank:%ld row:%ld value:0x%02lx (%ld)",
1059 bank, row, value)) {
1060 diag_printf("fuse_blow canceled\n");
1064 for (i = 0; i < 8; i++) {
1065 if (((value >> i) & 0x1) == 0) {
1068 if (fuse_blow(bank, row, i) != 0) {
1069 diag_printf("fuse_blow(bank: %ld, row: %ld, bit: %d failed\n",
1072 diag_printf("fuse_blow(bank: %ld, row: %ld, bit: %d successful\n",
1076 sense_fuse(bank, row, 0);
1078 diag_printf("Passing in wrong arguments: %d\n", argc);
1080 /* Reset to default string */
1081 strcpy(ready_to_blow, INIT_STRING);
1084 /* precondition: m>0 and n>0. Let g=gcd(m,n). */
1085 int gcd(int m, int n)
1089 if (n > m) {t = m; m = n; n = t;} /* swap */
1095 #define CLOCK_SRC_DETECT_MS 100
1096 #define CLOCK_IPG_DEFAULT 66500000
1097 #define CLOCK_SRC_DETECT_MARGIN 500000
1098 void mxc_show_clk_input(void)
1101 u32 c1, c2, diff, ipg_real, num = 0;
1102 u32 prcs = (readl(CCM_BASE_ADDR + CLKCTL_CCMR) >> 1) & 0x3;
1108 diag_printf("FPM enabled --> 32KHz input source\n");
1113 diag_printf("Error %d: unknown clock source %d\n", __LINE__, prcs);
1117 // enable GPT with IPG clock input
1118 writel(0x241, GPT_BASE_ADDR + GPTCR);
1120 writel(0, GPT_BASE_ADDR + GPTPR);
1122 c1 = readl(GPT_BASE_ADDR + GPTCNT);
1123 // use 32KHz input clock to get the delay
1124 hal_delay_us(CLOCK_SRC_DETECT_MS * 1000);
1125 c2 = readl(GPT_BASE_ADDR + GPTCNT);
1126 diff = (c2 > c1) ? (c2 - c1) : (0xFFFFFFFF - c1 + c2);
1128 ipg_real = diff * (1000 / CLOCK_SRC_DETECT_MS);
1130 if (ipg_real > (CLOCK_IPG_DEFAULT + CLOCK_SRC_DETECT_MARGIN)) {
1131 if (g_clock_src != FREQ_27MHZ)
1133 } else if (ipg_real < (CLOCK_IPG_DEFAULT - CLOCK_SRC_DETECT_MARGIN)) {
1134 if (g_clock_src != FREQ_26MHZ)
1138 diag_printf("Error: Actual clock input is %d MHz\n", num);
1139 diag_printf(" ipg_real=%d CLOCK_IPG_DEFAULT - CLOCK_SRC_DETECT_MARGIN=%d\n",
1140 ipg_real, CLOCK_IPG_DEFAULT - CLOCK_SRC_DETECT_MARGIN);
1141 diag_printf(" But clock source defined to be %d\n", g_clock_src);
1142 hal_delay_us(2000000);
1144 diag_printf("ipg_real=%d CLOCK_IPG_DEFAULT - CLOCK_SRC_DETECT_MARGIN=%d\n",
1145 ipg_real, CLOCK_IPG_DEFAULT - CLOCK_SRC_DETECT_MARGIN);
1146 diag_printf("clock source defined to be %d\n", g_clock_src);
1151 RedBoot_init(mxc_show_clk_input, RedBoot_INIT_LAST);
1153 void clock_spi_enable(unsigned int spi_clk)
1155 unsigned int reg = readl(SOC_CRM_PCCR1);
1158 writel(reg | (1 << 9), SOC_CRM_PCCR1);
1160 reg = readl(SOC_CRM_PCCR0);
1162 if (spi_clk == SPI1_CLK) {
1163 writel(reg | (1 << 31), SOC_CRM_PCCR0);
1164 gpio_request_mux(MX27_PIN_CSPI1_MOSI, GPIO_MUX_PRIMARY);
1165 gpio_request_mux(MX27_PIN_CSPI1_MISO, GPIO_MUX_PRIMARY);
1166 gpio_request_mux(MX27_PIN_CSPI1_SCLK, GPIO_MUX_PRIMARY);
1167 gpio_request_mux(MX27_PIN_CSPI1_RDY, GPIO_MUX_PRIMARY);
1168 gpio_request_mux(MX27_PIN_CSPI1_SS0, GPIO_MUX_PRIMARY);
1169 gpio_request_mux(MX27_PIN_CSPI1_SS1, GPIO_MUX_PRIMARY);
1170 gpio_request_mux(MX27_PIN_CSPI1_SS2, GPIO_MUX_PRIMARY);
1171 } else if (spi_clk == SPI2_CLK) {
1172 writel(reg | (1 << 30), SOC_CRM_PCCR0);