1 //==========================================================================
5 // 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 1022
60 #define AHB_DIV_MAX 16
62 //#define CPLM_SETUP (1 << 31)
65 #if (PLL_REF_CLK == FREQ_32768HZ) || (PLL_REF_CLK == FREQ_32000HZ)
66 #define PLL_MFD_FIXED 1024
68 #if (PLL_REF_CLK == FREQ_26MHZ)
69 #define PLL_MFD_FIXED (26 * 16) // =416
72 #define PLL_FREQ_MAX (2 * PLL_REF_CLK * PLL_MFI_MAX)
73 #define PLL_FREQ_MIN ((2 * PLL_REF_CLK * PLL_MFI_MIN) / PLL_PD_MAX)
74 #define AHB_CLK_MAX 133333333
75 #define IPG_CLK_MAX (AHB_CLK_MAX / 2)
76 #define NFC_CLK_MAX 33333333
78 #define ERR_WRONG_CLK -1
82 #define ERR_NO_PRESC -5
84 u32 pll_clock(enum plls pll);
85 u32 get_main_clock(enum main_clocks clk);
86 u32 get_peri_clock(enum peri_clocks clk);
88 static void clock_setup(int argc, char *argv[]);
89 static void clko(int argc, char *argv[]);
92 "Setup/Display clock (max AHB=133MHz, max IPG=66.5MHz)\nSyntax:",
93 "[<core clock in MHz> [:<AHB-to-core divider>[:<IPG-to-AHB divider>]]] \n\n\
94 If a divider is zero or no divider is specified, the optimal divider values \n\
95 will be chosen. Examples:\n\
96 [clock] -> Show various clocks\n\
97 [clock 266] -> Core=266 AHB=133 IPG=66.5\n\
98 [clock 350] -> Core=350 AHB=117 IPG=58.5\n\
99 [clock 266:4] -> Core=266 AHB=66.5(Core/4) IPG=66.5\n\
100 [clock 266:4:2] -> Core=266 AHB=66.5(Core/4) IPG=33.25(AHB/2)\n",
105 * This is to calculate various parameters based on reference clock and
106 * targeted clock based on the equation:
107 * t_clk = 2*ref_freq*(mfi + mfn/(mfd+1))/(pd+1)
108 * This calculation is based on a fixed MFD value for simplicity.
110 * @param ref reference clock freq
111 * @param target targeted clock in HZ
112 * @param p_pd calculated pd value (pd value from register + 1) upon return
113 * @param p_mfi calculated actual mfi value upon return
114 * @param p_mfn calculated actual mfn value upon return
115 * @param p_mfd fixed mfd value (mfd value from register + 1) upon return
117 * @return 0 if successful; non-zero otherwise.
119 int calc_pll_params(u32 ref, u32 target, u32 *p_pd,
120 u32 *p_mfi, u32 *p_mfn, u32 *p_mfd)
122 u64 pd, mfi, mfn, n_target = (u64)target, n_ref = (u64)ref;
124 // Make sure targeted freq is in the valid range. Otherwise the
125 // following calculation might be wrong!!!
126 if (target < PLL_FREQ_MIN || target > PLL_FREQ_MAX) {
127 return ERR_WRONG_CLK;
129 // Use n_target and n_ref to avoid overflow
130 for (pd = 1; pd <= PLL_PD_MAX; pd++) {
131 mfi = (n_target * pd) / (2 * n_ref);
132 if (mfi > PLL_MFI_MAX) {
134 } else if (mfi < 5) {
139 // Now got pd and mfi already
140 mfn = (((n_target * pd) / 2 - n_ref * mfi) * PLL_MFD_FIXED) / n_ref;
141 // Check mfn within limit and mfn < denominator
142 if (mfn > PLL_MFN_MAX || mfn >= PLL_MFD_FIXED) {
146 if (pd > PLL_PD_MAX) {
152 *p_mfd = PLL_MFD_FIXED;
157 * This function assumes the expected core clock has to be changed by
158 * modifying the PLL. This is NOT true always but for most of the times,
159 * it is. So it assumes the PLL output freq is the same as the expected
160 * core clock (presc=1) unless the core clock is less than PLL_FREQ_MIN.
161 * In the latter case, it will try to increase the presc value until
162 * (presc*core_clk) is greater than PLL_FREQ_MIN. It then makes call to
163 * calc_pll_params() and obtains the values of PD, MFI,MFN, MFD based
164 * on the targeted PLL and reference input clock to the PLL. Lastly,
165 * it sets the register based on these values along with the dividers.
166 * Note 1) There is no value checking for the passed-in divider values
167 * so the caller has to make sure those values are sensible.
168 * 2) Also adjust the NFC divider such that the NFC clock doesn't
169 * exceed NFC_CLK_MAX (which is 33MHz now).
171 * @param ref pll input reference clock (32KHz or 26MHz)
172 * @param core_clk core clock in Hz
173 * @param ahb_div ahb divider to divide the core clock to get ahb clock
174 * (ahb_div - 1) needs to be set in the register
175 * @param ipg_div ipg divider to divide the ahb clock to get ipg clock
176 * (ipg_div - 1) needs to be set in the register
177 # @return 0 if successful; non-zero otherwise
179 int configure_clock(u32 ref, u32 core_clk, u32 ahb_div, u32 ipg_div)
181 u32 pll, presc = 1, pd, mfi, mfn, mfd, brmo = 1, cscr, mpctl0;
185 // assume pll default to core clock first
187 // when core_clk >= PLL_FREQ_MIN, the presc can be 1.
188 // Otherwise, need to calculate presc value below and adjust the targeted pll
189 if (core_clk < PLL_FREQ_MIN) {
190 for (presc = 1; presc <= PRESC_MAX; presc++) {
191 if ((core_clk * presc) > PLL_FREQ_MIN) {
195 if (presc == (PRESC_MAX + 1)) {
196 diag_printf("can't make presc=%d\n", presc);
199 pll = core_clk * presc;
201 // pll is now the targeted pll output. Use it along with ref input clock
202 // to get pd, mfi, mfn, mfd
203 if ((ret = calc_pll_params(ref, pll, &pd, &mfi, &mfn, &mfd)) != 0) {
204 diag_printf("can't find pll parameters: %d\n", ret);
208 // blindly increase divider first to avoid too fast ahbclk and ipgclk
209 // in case the core clock increases too much
210 cscr = readl(MX21_CRM_BASE + MX21_CRM_CSCR);
212 // increase the dividers. should work even when core clock is 780MHz
213 // which is unlikely true.
214 cscr |= (3 << 29) | (5 << 10) | (1 << 9);
215 writel(cscr, MX21_CRM_BASE + MX21_CRM_CSCR);
217 // update PLL register
218 if ((mfd < (10 * mfn)) && ((10 * mfn) < (9 * mfd)))
221 writel(1 << 6, MX21_CRM_BASE + MX21_CRM_MPCTL1);
223 mpctl0 = readl(MX21_CRM_BASE + MX21_CRM_MPCTL0);
224 mpctl0 = (mpctl0 & 0xC000C000) |
230 writel(mpctl0, MX21_CRM_BASE + MX21_CRM_MPCTL0);
232 writel((cscr | (1 << 21)), MX21_CRM_BASE + MX21_CRM_CSCR);
233 // check the LF bit to insure lock
234 while ((readl(MX21_CRM_BASE + MX21_CRM_MPCTL1) & (1 << 15)) == 0);
235 // have to add some delay for new values to take effect
236 for (i = 0; i < 10000; i++);
238 // PLL locked already so use the new divider values
239 cscr = readl(MX21_CRM_BASE + MX21_CRM_CSCR);
241 cscr |= ((presc - 1) << 29) | ((ahb_div - 1) << 10) | ((ipg_div - 1) << 9);
242 writel(cscr, MX21_CRM_BASE + MX21_CRM_CSCR);
244 // Make sure optimal NFC clock but less than NFC_CLK_MAX
245 for (nfc_div = 1; nfc_div <= 16; nfc_div++) {
246 if ((core_clk / nfc_div) <= NFC_CLK_MAX) {
250 pcdr0 = readl(MX21_CRM_BASE + MX21_CRM_PCDR0);
251 writel(((pcdr0 & 0xFFFF0FFF) | ((nfc_div - 1) << 12)),
252 MX21_CRM_BASE + MX21_CRM_PCDR0);
257 static void clock_setup(int argc,char *argv[])
259 u32 i, core_clk, ipg_div, data[3],
260 ahb_div, ahb_clk, ipg_clk;
265 for (i = 0; i < 3; i++) {
267 if (!parse_num(*(&argv[1]), &temp, &argv[1], ":")) {
268 diag_printf("Error: Invalid parameter\n");
274 core_clk = data[0] * SZ_DEC_1M;
275 ahb_div = data[1]; // actual register field + 1
276 ipg_div = data[2]; // actual register field + 1
278 if (core_clk < (PLL_FREQ_MIN / PRESC_MAX) || core_clk > PLL_FREQ_MAX) {
279 diag_printf("Targeted core clock should be within [%d - %d]\n",
280 PLL_FREQ_MIN / PRESC_MAX, PLL_FREQ_MAX);
284 // find the ahb divider
285 if (ahb_div > AHB_DIV_MAX) {
286 diag_printf("Invalid AHB divider: %d. Maximum value is %d\n",
287 ahb_div, AHB_DIV_MAX);
291 // no AHBCLK divider specified
292 for (ahb_div = 1; ; ahb_div++) {
293 if ((core_clk / ahb_div) <= AHB_CLK_MAX) {
298 if (ahb_div > AHB_DIV_MAX || (core_clk / ahb_div) > AHB_CLK_MAX) {
299 diag_printf("Can't make AHB=%d since max=%d\n",
300 core_clk / ahb_div, AHB_CLK_MAX);
304 // find the ipg divider
305 ahb_clk = core_clk / ahb_div;
306 if (ipg_div > IPG_DIV_MAX) {
307 diag_printf("Invalid IPG divider: %d. Maximum value is %d\n",
308 ipg_div, IPG_DIV_MAX);
312 ipg_div++; // At least =1
313 if (ahb_clk > IPG_CLK_MAX)
314 ipg_div++; // Make it =2
316 if (ipg_div > IPG_DIV_MAX || (ahb_clk / ipg_div) > IPG_CLK_MAX) {
317 diag_printf("Can't make IPG=%d since max=%d\n",
318 (ahb_clk / ipg_div), IPG_CLK_MAX);
321 ipg_clk = ahb_clk / ipg_div;
323 diag_printf("Trying to set core=%d ahb=%d ipg=%d...\n",
324 core_clk, ahb_clk, ipg_clk);
326 // stop the serial to be ready to adjust the clock
327 hal_delay_us(100000);
328 cyg_hal_plf_serial_stop();
330 ret = configure_clock(PLL_REF_CLK, core_clk, ahb_div, ipg_div);
331 // restart the serial driver
332 cyg_hal_plf_serial_init();
333 hal_delay_us(100000);
336 diag_printf("Failed to setup clock: %d\n", ret);
339 diag_printf("\n<<<New clock setting>>>\n");
341 // Now printing clocks
343 diag_printf("\nMPLL\t\tSPLL\n");
344 diag_printf("=========================\n");
345 diag_printf("%-16d%-16d\n\n", pll_clock(MCU_PLL), pll_clock(SER_PLL));
346 diag_printf("CPU\t\tAHB\t\tIPG\t\tNFC\t\tUSB\n");
347 diag_printf("========================================================================\n");
348 diag_printf("%-16d%-16d%-16d%-16d%-16d\n\n",
349 get_main_clock(CPU_CLK),
350 get_main_clock(AHB_CLK),
351 get_main_clock(IPG_CLK),
352 get_main_clock(NFC_CLK),
353 get_main_clock(USB_CLK));
355 diag_printf("PER1\t\tPER2\t\tPER3\t\tPER4\n");
356 diag_printf("===========================================");
357 diag_printf("=============\n");
359 diag_printf("%-16d%-16d%-16d%-16d\n\n",
360 get_peri_clock(PER_CLK1),
361 get_peri_clock(PER_CLK2),
362 get_peri_clock(PER_CLK3),
363 get_peri_clock(PER_CLK4));
365 diag_printf("FIRI\t\tSSI1\t\tSSI2\n");
366 diag_printf("========================================\n");
367 diag_printf("%-16d%-16d%-16d\n\n",
368 get_peri_clock(FIRI_BAUD),
369 get_peri_clock(SSI1_BAUD),
370 get_peri_clock(SSI2_BAUD));
371 diag_printf("PERCLK: 1-<UART|GPT|PWM> 2-<SDHC|CSPI> 3-<LCDC> 4-<CSI>\n");
375 * This function returns the PLL output value in Hz based on pll.
377 u32 pll_clock(enum plls pll)
379 u64 mfi, mfn, mfd, pdf, ref_clk, pll_out;
380 u64 reg = readl(pll);
382 pdf = (reg >> 26) & 0xF;
383 mfd = (reg >> 16) & 0x3FF;
384 mfi = (reg >> 10) & 0xF;
385 mfi = (mfi <= 5) ? 5: mfi;
388 ref_clk = PLL_REF_CLK;
390 pll_out = (2 * ref_clk * mfi + ((2 * ref_clk * mfn) / (mfd + 1))) /
397 * This function returns the main clock value in Hz.
399 u32 get_main_clock(enum main_clocks clk)
401 u32 presc, ahb_div, ipg_pdf, nfc_div;
402 u32 ret_val = 0, usb_div;
403 u32 cscr = readl(MX21_CRM_BASE + MX21_CRM_CSCR);
404 u32 pcdr0 = readl(MX21_CRM_BASE + MX21_CRM_PCDR0);
406 presc = (cscr >> 29) + 1;
410 ret_val = pll_clock(MCU_PLL) / presc;
413 ahb_div = ((cscr >> 10) & 0xF) + 1;
414 ret_val = pll_clock(MCU_PLL) / (presc * ahb_div);
417 ahb_div = ((cscr >> 10) & 0xF) + 1;
418 ipg_pdf = ((cscr >> 9) & 0x1) + 1;
419 ret_val = pll_clock(MCU_PLL) / (presc * ahb_div * ipg_pdf);
422 nfc_div = ((pcdr0 >> 12) & 0xF) + 1;
424 ret_val = pll_clock(MCU_PLL) / (presc * nfc_div);
427 usb_div = ((cscr >> 26) & 0x7) + 1;
428 ret_val = pll_clock(SER_PLL) / usb_div;
431 diag_printf("Unknown clock: %d\n", clk);
439 * This function returns the peripheral clock value in Hz.
441 u32 get_peri_clock(enum peri_clocks clk)
443 u32 ret_val = 0, div;
444 u32 pcdr0 = readl(MX21_CRM_BASE + MX21_CRM_PCDR0);
445 u32 pcdr1 = readl(MX21_CRM_BASE + MX21_CRM_PCDR1);
446 u32 cscr = readl(MX21_CRM_BASE + MX21_CRM_CSCR);
450 div = (pcdr1 & 0x3F) + 1;
451 ret_val = pll_clock(MCU_PLL) / div;
454 div = ((pcdr1 >> 8) & 0x3F) + 1;
455 ret_val = pll_clock(MCU_PLL) / div;
458 div = ((pcdr1 >> 16) & 0x3F) + 1;
459 ret_val = pll_clock(MCU_PLL) / div;
462 div = ((pcdr1 >> 24) & 0x3F) + 1;
463 ret_val = pll_clock(MCU_PLL) / div;
466 div = (pcdr0 >> 16) & 0x3F;
469 if ((cscr & (1 << 19)) != 0) {
470 // This takes care of 0.5*SSIDIV[0] by x2
471 ret_val = (2 * pll_clock(MCU_PLL)) / div;
473 ret_val = (2 * pll_clock(SER_PLL)) / div;
477 div = (pcdr0 >> 26) & 0x3F;
480 if ((cscr & (1 << 20)) != 0) {
481 ret_val = (2 * pll_clock(MCU_PLL)) / div;
483 ret_val = (2 * pll_clock(SER_PLL)) / div;
487 div = (pcdr0 & 0x1F) + 1;
488 if ((cscr & (1 << 18)) == 0) {
489 ret_val = pll_clock(MCU_PLL) / div;
491 ret_val = (2 * pll_clock(SER_PLL)) / div;
495 diag_printf("%s(): This clock: %d not supported yet \n",
504 "Select clock source for CLKO (TP1 on the CPU daughter card)",
505 " The output clock is the actual clock source freq. Default is FCLK\n\
506 Note that the module clock will be turned on for reading!\n\
507 <0> - display current clko selection \n\
510 <3> - CLK26M (may see nothing if 26MHz Crystal is not connected) \n\
511 <4> - MPLL Reference CLK \n\
512 <5> - SPLL Reference CLK \n\
517 <10> - IPG_CLK (PERCLK) \n\
522 <15> - SSI 1 Baud \n\
523 <16> - SSI 2 Baud \n\
526 <19> - CLK48M Always \n\
527 <20> - CLK32K Always \n\
529 <22> - CLK48DIV_CLKO",
533 static u8* clko_name[] ={
537 "CLK26M (may see nothing if 26MHz Crystal is not connected)",
538 "MPLL Reference CLK",
539 "SPLL Reference CLK",
559 // This has to agree with the above table
569 #define CLKO_MAX_INDEX (sizeof(clko_name) / sizeof(u8*))
571 static void clko(int argc,char *argv[])
573 u32 action = 0, ccsr;
575 if (!scan_opts(argc, argv, 1, 0, 0, (void*) &action,
576 OPTION_ARG_TYPE_NUM, "action"))
579 if (action >= CLKO_MAX_INDEX) {
580 diag_printf("%d is not supported\n\n", action);
584 ccsr = readl(MX21_CRM_BASE + MX21_CRM_CCSR);
587 // turn on these clocks
590 writel(readl(MX21_CRM_BASE + MX21_CRM_PCCR0) | (1 << 18),
591 MX21_CRM_BASE + MX21_CRM_PCCR0);
594 writel(readl(MX21_CRM_BASE + MX21_CRM_PCCR0) | (1 << 22),
595 MX21_CRM_BASE + MX21_CRM_PCCR0);
598 writel(readl(MX21_CRM_BASE + MX21_CRM_PCCR0) | (1 << 17),
599 MX21_CRM_BASE + MX21_CRM_PCCR0);
602 writel(readl(MX21_CRM_BASE + MX21_CRM_PCCR0) | (1 << 16),
603 MX21_CRM_BASE + MX21_CRM_PCCR0);
606 writel(readl(MX21_CRM_BASE + MX21_CRM_PCCR0) | (1 << 19),
607 MX21_CRM_BASE + MX21_CRM_PCCR0);
610 writel(readl(MX21_CRM_BASE + MX21_CRM_PCCR0) | (1 << 20),
611 MX21_CRM_BASE + MX21_CRM_PCCR0);
614 ccsr = (ccsr & (~0x1F)) + action - 1;
615 writel(ccsr, MX21_CRM_BASE + MX21_CRM_CCSR);
616 diag_printf("Set clko to ");
619 ccsr = readl(MX21_CRM_BASE + MX21_CRM_CCSR);
620 diag_printf("%s\n", clko_name[(ccsr & 0x1F) + 1]);
621 diag_printf("CCSR register[0x%x] = 0x%x\n",
622 (MX21_CRM_BASE + MX21_CRM_CCSR), ccsr);
625 extern int flash_program(void *_addr, void *_data, int len, void **err_addr);
626 extern int flash_erase(void *addr, int len, void **err_addr);
628 void auto_flash_start(void)
632 int nor_update = 1; //todo: need to support NAND
633 u32 src = readl(SERIAL_DOWNLOAD_SRC_REG);
634 u32 dst = readl(SERIAL_DOWNLOAD_TGT_REG);
635 u32 sz = readl(SERIAL_DOWNLOAD_SZ_REG);
637 if (readl(SERIAL_DOWNLOAD_MAGIC_REG) != SERIAL_DOWNLOAD_MAGIC) {
642 // Erase area to be programmed
643 if ((stat = flash_erase((void *)dst, sz, (void **)&err_addr)) != 0) {
644 diag_printf("BEADDEAD\n");
647 diag_printf("BEADBEEF\n");
649 if ((stat = flash_program((void *)dst, (void *)src, sz,
650 (void **)&err_addr)) != 0) {
651 diag_printf("BEADFEEF\n");
654 diag_printf("BEADCEEF\n");
657 RedBoot_init(auto_flash_start, RedBoot_INIT_LAST);