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 ARM_DIV_MAX 6 //should be enough even though max is 12
57 #define IPG_DIV_MAX 16
58 #define AHB_DIV_MAX 16
59 #define NFC_DIV_MAX 16
61 #define REF_IN_CLK_NUM 4
62 struct fixed_pll_mfd {
66 const struct fixed_pll_mfd fixed_mfd[REF_IN_CLK_NUM] = {
67 {FREQ_CKIH_26M, 26 * 16}, // 416
69 {2 * FREQ_CKIH_26M, 26 * 16}, // 416
80 #define PLL_FREQ_MAX(_ref_clk_) (2 * _ref_clk_ * PLL_MFI_MAX)
81 #define PLL_FREQ_MIN(_ref_clk_) ((2 * _ref_clk_ * (PLL_MFI_MIN - 1)) / PLL_PD_MAX)
82 #define AHB_CLK_MAX 133333333
83 #define IPG_CLK_MAX (AHB_CLK_MAX / 2)
84 #define NFC_CLK_MAX 25000000
86 #define ERR_WRONG_CLK -1
90 #define ERR_NO_ARM_DIV -5
91 #define ERR_NO_AHB_DIV -6
93 int gcd(int m, int n);
95 static void clock_setup(int argc, char *argv[]);
96 static void ckol(int argc, char *argv[]);
97 static void ckoh(int argc, char *argv[]);
99 static volatile u32 *crm_ap_base = REG32_PTR(CRM_AP_BASE_ADDR);
101 static volatile u32 *pll_base[] =
103 REG32_PTR(PLL0_BASE_ADDR), // MCU PLL
104 REG32_PTR(PLL1_BASE_ADDR), // DSP PLL
105 REG32_PTR(PLL2_BASE_ADDR), // USB PLL
108 #define NOT_ON_VAL 0xDEADBEEF
111 "Setup/Display clock (max AHB=133MHz, max IPG=66.5MHz)\nSyntax:",
112 "[<core clock in MHz> [:<AHB-to-core divider>[:<IPG-to-AHB divider>]]] \n\n\
113 If a divider is zero or no divider is specified, the optimal divider values \n\
114 will be chosen. Examples:\n\
115 [clock] -> Show various clocks\n\
116 [clock 532] -> Core=532 AHB=133 IPG=66.5\n\
117 [clock 399] -> Core=399 AHB=133 IPG=66.5\n\
118 [clock 399:6] -> Core=399 AHB=66.5(Core/8) IPG=66.5\n\
119 [clock 399:6:2] -> Core=532 AHB=66.5(Core/8) IPG=33.25(AHB/2)\n",
124 * This is to calculate various parameters based on reference clock and
125 * targeted clock based on the equation:
126 * t_clk = 2*ref_freq*(mfi + mfn/(mfd+1))/(pd+1)
127 * This calculation is based on a fixed MFD value for simplicity.
129 * @param ref reference clock freq in Hz
130 * @param target targeted clock in Hz
131 * @param p_pd calculated pd value (pd value from register + 1) upon return
132 * @param p_mfi calculated actual mfi value upon return
133 * @param p_mfn calculated actual mfn value upon return
134 * @param p_mfd fixed mfd value (mfd value from register + 1) upon return
136 * @return 0 if successful; non-zero otherwise.
138 int calc_pll_params(u32 ref, u32 target, struct pll_param *pll)
140 u64 pd, mfi = 1, mfn, mfd, n_target = target, n_ref = ref, i;
142 // make sure targeted freq is in the valid range. Otherwise the
143 // following calculation might be wrong!!!
144 if (n_target < PLL_FREQ_MIN(ref) || n_target > PLL_FREQ_MAX(ref))
145 return ERR_WRONG_CLK;
147 if (i == REF_IN_CLK_NUM)
148 return ERR_WRONG_CLK;
149 if (fixed_mfd[i].ref_clk_hz == ref) {
150 mfd = fixed_mfd[i].mfd;
154 // use n_target and n_ref to avoid overflow
155 for (pd = 1; pd <= PLL_PD_MAX; pd++) {
156 mfi = (n_target * pd) / (2 * n_ref);
157 if (mfi > PLL_MFI_MAX)
163 // Now got pd and mfi already
164 mfn = (((n_target * pd) / 2 - n_ref * mfi) * mfd) / n_ref;
165 #ifdef CMD_CLOCK_DEBUG
166 diag_printf("%d: ref=%d, target=%d, pd=%d, mfi=%d,mfn=%d, mfd=%d\n",
167 __LINE__, ref, (u32)n_target, (u32)pd, (u32)mfi, (u32)mfn, (u32)mfd);
174 pll->mfn = (u32)(mfn / i);
175 pll->mfd = (u32)(mfd / i);
180 * This function assumes the expected core clock has to be changed by
181 * modifying the PLL. This is NOT true always but for most of the times,
182 * it is. So it assumes the PLL output freq is the same as the expected
183 * core clock (arm_div=1) unless the core clock is less than PLL_FREQ_MIN.
184 * In the latter case, it will try to increase the arm_div value until
185 * (arm_div*core_clk) is greater than PLL_FREQ_MIN. It then makes call to
186 * calc_pll_params() and obtains the values of PD, MFI,MFN, MFD based
187 * on the targeted PLL and reference input clock to the PLL. Lastly,
188 * it sets the register based on these values along with the dividers.
189 * Note 1) There is no value checking for the passed-in divider values
190 * so the caller has to make sure those values are sensible.
191 * 2) Also adjust the NFC divider such that the NFC clock doesn't
192 * exceed NFC_CLK_MAX.
193 * 3) This function should not have allowed diag_printf() calls since
194 * the serial driver has been stoped. But leave then here to allow
195 * easy debugging by NOT calling the cyg_hal_plf_serial_stop().
196 * 4) The IPG divider doesn't go through AHB divider
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 core 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 int configure_clock(u32 ref, u32 core_clk, u32 ahb_div, u32 ipg_div)
208 u32 pll, arm_div = 1, nfc_div, acdr, acder2;
209 struct pll_param pll_param;
212 // assume pll default to core clock first
214 // when core_clk >= PLL_FREQ_MIN, the arm_div can be 1.
215 // Otherwise, need to calculate arm_div value below and adjust the targeted pll
216 if (core_clk < PLL_FREQ_MIN(ref)) {
217 for (arm_div = 1; arm_div <= ARM_DIV_MAX; arm_div++) {
218 if ((core_clk * arm_div) > PLL_FREQ_MIN(ref)) {
222 if (arm_div == (ARM_DIV_MAX + 1)) {
223 diag_printf("can't make arm_div=%d\n", arm_div);
224 return ERR_NO_ARM_DIV;
226 pll = core_clk * arm_div;
229 // get nfc_div - make sure optimal NFC clock but less than NFC_CLK_MAX
230 for (nfc_div = 1; nfc_div <= NFC_DIV_MAX; nfc_div++) {
231 if ((pll / (ahb_div * nfc_div)) <= NFC_CLK_MAX) {
236 // pll is now the targeted pll output. Use it along with ref input clock
237 // to get pd, mfi, mfn, mfd
238 if ((ret = calc_pll_params(ref, pll, &pll_param)) != 0) {
239 diag_printf("can't find pll parameters: %d\n", ret);
242 #ifdef CMD_CLOCK_DEBUG
243 diag_printf("ref=%d, pll=%d, pd=%d, mfi=%d,mfn=%d, mfd=%d\n",
244 ref, pll, pll_param.pd, pll_param.mfi, pll_param.mfn, pll_param.mfd);
246 acdr = (((arm_div == 1) ? 0x8 : (arm_div - 2)) << 8) |
247 (((ahb_div == 16)? 0x0 : ahb_div) << 4) |
248 ((ipg_div == 16)? 0x0 : ipg_div);
250 acder2 = (readl(CRM_AP_BASE_ADDR + CRM_AP_ACDER2) & 0xFFF0FFFF) |
251 ((nfc_div - 1) << 16);
253 // switch to ap_ref_clk
254 writel(readl(CRM_AP_BASE_ADDR + CRM_AP_ACSR) & (~0x1),
255 CRM_AP_BASE_ADDR + CRM_AP_ACSR);
257 // change the dividers
258 writel(acdr, CRM_AP_BASE_ADDR + CRM_AP_ACDR);
259 writel(acder2, CRM_AP_BASE_ADDR + CRM_AP_ACDER2);
261 // adjust pll settings
262 writel(((pll_param.pd - 1) << 0) | (pll_param.mfi << 4),
263 PLL0_BASE_ADDR + PLL_DP_OP);
264 writel(pll_param.mfn, PLL0_BASE_ADDR + PLL_DP_MFN);
265 writel(pll_param.mfd - 1, PLL0_BASE_ADDR + PLL_DP_MFD);
266 writel(((pll_param.pd - 1) << 0) | (pll_param.mfi << 4),
267 PLL0_BASE_ADDR + PLL_DP_HFS_OP);
268 writel(pll_param.mfn, PLL0_BASE_ADDR + PLL_DP_HFS_MFN);
269 writel(pll_param.mfd - 1, PLL0_BASE_ADDR + PLL_DP_HFS_MFD);
271 // switch back to pll
272 writel(readl(CRM_AP_BASE_ADDR + CRM_AP_ACSR) | 0x1,
273 CRM_AP_BASE_ADDR + CRM_AP_ACSR);
278 static void clock_setup(int argc,char *argv[])
280 u32 i, core_clk, ipg_div, data[3], uart1_baud, uart3_baud, ssi1_baud;
281 u32 ssi2_baud, csi_baud, ahb_div, ahb_clk, ipg_clk, clk_sel, ref_clk;
286 for (i = 0; i < 3; i++) {
288 if (!parse_num(*(&argv[1]), &temp, &argv[1], ":")) {
289 diag_printf("Error: Invalid parameter\n");
295 core_clk = data[0] * SZ_DEC_1M;
296 ahb_div = data[1]; // actual register field + 1
297 ipg_div = data[2]; // actual register field + 1
299 // since only support set clock for the AP domain, get ref input clock
300 // for the AP domain.
301 clk_sel = MXC_GET_FIELD(readl(PLL0_BASE_ADDR + PLL_DP_CTL), 2, 8);
302 ref_clk = fixed_mfd[clk_sel].ref_clk_hz;
304 if (core_clk < (PLL_FREQ_MIN(ref_clk) / ARM_DIV_MAX) ||
305 core_clk > PLL_FREQ_MAX(ref_clk)) {
306 diag_printf("Targeted core clock should be within [%d - %d]\n",
307 PLL_FREQ_MIN(ref_clk) / ARM_DIV_MAX,
308 PLL_FREQ_MAX(ref_clk));
312 // find the ahb divider
313 if (ahb_div > AHB_DIV_MAX) {
314 diag_printf("Invalid AHB divider: %d. Maximum value is %d\n",
315 ahb_div, AHB_DIV_MAX);
319 // no HCLK divider specified
320 for (ahb_div = 1; ; ahb_div++) {
321 if ((core_clk / ahb_div) <= AHB_CLK_MAX)
325 if (ahb_div > AHB_DIV_MAX || (core_clk / ahb_div) > AHB_CLK_MAX) {
326 diag_printf("Can't make AHB=%d since max=%d\n",
327 core_clk / ahb_div, AHB_CLK_MAX);
331 // find the ipg divider
332 ahb_clk = core_clk / ahb_div;
334 ipg_div++; // At least =1
335 if (ahb_clk > IPG_CLK_MAX)
336 ipg_div++; // Make it =2
338 // adjust ipg_div since IPG clock doesn't go through AHB divider
340 ipg_clk = core_clk / ipg_div;
341 if (ipg_div > IPG_DIV_MAX || ipg_clk > IPG_CLK_MAX) {
342 if (ipg_div > IPG_DIV_MAX)
343 diag_printf("Invalid IPG divider: %d. Max is: %d\n",
344 ipg_div / ahb_div, IPG_DIV_MAX / ahb_div);
346 diag_printf("Can't make IPG=%dHz since max=%dHz\n",
347 ipg_clk, IPG_CLK_MAX);
351 diag_printf("Trying to set core=%d ahb=%d ipg=%d...\n",
352 core_clk, ahb_clk, ipg_clk);
354 // stop the serial to be ready to adjust the clock
355 hal_delay_us(100000);
356 cyg_hal_plf_serial_stop();
358 ret = configure_clock(ref_clk, core_clk, ahb_div, ipg_div);
359 // restart the serial driver
360 cyg_hal_plf_serial_init();
361 hal_delay_us(100000);
364 diag_printf("Failed to setup clock: %d\n", ret);
367 diag_printf("\n<<<New clock setting>>>\n");
369 // Now printing clocks
371 diag_printf("\nMCUPLL\t\tUSBPLL\t\tDSPPLL\n");
372 diag_printf("========================================\n");
373 diag_printf("%-16d%-16d%-16d\n\n", pll_clock(PLL0), pll_clock(PLL2),
375 diag_printf("CPU\t\tAHB\t\tIPG\t\tNFC\t\tUSB\n");
376 diag_printf("===========================================");
377 diag_printf("=============================\n");
378 diag_printf("%-16d%-16d%-16d%-16d%-16d\n\n",
379 get_main_clock(CPU_CLK),
380 get_main_clock(AHB_CLK),
381 get_main_clock(IPG_CLK),
382 get_main_clock(NFC_CLK),
383 get_main_clock(USB_CLK));
385 uart1_baud = get_peri_clock(UART1_BAUD);
386 uart3_baud = get_peri_clock(UART3_BAUD);
387 ssi1_baud = get_peri_clock(SSI1_BAUD);
388 ssi2_baud = get_peri_clock(SSI2_BAUD);
389 csi_baud = get_peri_clock(CSI_BAUD);
391 diag_printf("UART1/2\t\tUART3\t\tSSI1\t\tSSI2\t\tCSI\n");
392 diag_printf("===========================================");
393 diag_printf("=============================\n");
395 (uart1_baud != NOT_ON_VAL) ? diag_printf("%-16d", uart1_baud) :
396 diag_printf("%-16s", "OFF");
397 (uart3_baud != NOT_ON_VAL) ? diag_printf("%-16d", uart3_baud) :
398 diag_printf("%-16s", "OFF");
399 (ssi1_baud != NOT_ON_VAL) ? diag_printf("%-16d", ssi1_baud) :
400 diag_printf("%-16s", "OFF");
401 (ssi2_baud != NOT_ON_VAL) ? diag_printf("%-16d", ssi2_baud) :
402 diag_printf("%-16s", "OFF");
403 (csi_baud != NOT_ON_VAL) ? diag_printf("%-16d", csi_baud ) :
404 diag_printf("%-16s", "OFF");
409 * This function returns the PLL output value in Hz based on pll.
411 u32 pll_clock(enum plls pll)
413 u64 mfi, mfn, mfd, pdf, ref_clk, pll_out, sign;
414 u64 dp_op, dp_mfd, dp_mfn, clk_sel;
416 clk_sel = MXC_GET_FIELD(pll_base[pll][PLL_DP_CTL >> 2], 2, 8);
417 ref_clk = fixed_mfd[clk_sel].ref_clk_hz;
419 if ((pll_base[pll][PLL_DP_CTL >> 2] & 0x80) == 0) {
420 dp_op = pll_base[pll][PLL_DP_OP >> 2];
421 dp_mfd = pll_base[pll][PLL_DP_MFD >> 2];
422 dp_mfn = pll_base[pll][PLL_DP_MFN >> 2];
424 dp_op = pll_base[pll][PLL_DP_HFS_OP >> 2];
425 dp_mfd = pll_base[pll][PLL_DP_HFS_MFD >> 2];
426 dp_mfn = pll_base[pll][PLL_DP_HFS_MFN >> 2];
429 mfi = (dp_op >> 4) & 0xF;
430 mfi = (mfi <= 5) ? 5: mfi;
431 mfd = dp_mfd & 0x07FFFFFF;
432 mfn = dp_mfn & 0x07FFFFFF;
434 sign = (mfn < 0x4000000) ? 0: 1;
435 mfn = (mfn <= 0x4000000) ? mfn: (0x8000000 - mfn);
438 pll_out = (2 * ref_clk * mfi + ((2 * ref_clk * mfn) / (mfd + 1))) /
441 pll_out = (2 * ref_clk * mfi - ((2 * ref_clk * mfn) / (mfd + 1))) /
448 const u32 CRM_SMALL_DIV[] = {2, 3, 4, 5, 6, 8, 10, 12};
451 * This function returns the main clock dividers.
453 u32 clock_divider(enum main_clocks clk)
458 acdr = crm_ap_base[CRM_AP_ACDR >> 2];
459 acder2 = crm_ap_base[CRM_AP_ACDER2 >> 2];
463 div = (acdr >> 8) & 0xF;
464 div = (div > 7) ? 1 : (CRM_SMALL_DIV[div]);
467 div = (acdr >> 4) & 0xF;
468 div = (div == 0) ? 16 : div;
471 div = (acdr >> 0) & 0xF;
472 div = (div == 0) ? 16 : div;
475 div = ((acder2 >> 16) & 0xF) + 1;
478 div = (acder2 >> 8) & 0xF;
479 div = (div > 7) ? 1 : (CRM_SMALL_DIV[div]);
482 diag_printf("Wrong clock: %d\n", clk);
490 * This function returns the peripheral clock dividers.
492 u32 clock_peri_divider(enum peri_clocks clk)
495 u32 apra, acder1, acder2;
497 apra = crm_ap_base[CRM_AP_APRA >> 2];
498 acder1 = crm_ap_base[CRM_AP_ACDER1 >> 2];
499 acder2 = crm_ap_base[CRM_AP_ACDER2 >> 2];
505 div = (div > 7) ? 1 : (CRM_SMALL_DIV[div]);
508 div = (apra >> 17) & 0xF;
509 div = (div > 7) ? 1 : (CRM_SMALL_DIV[div]);
513 //double the divider to avoid FP
514 div = (div == 0 || div == 1) ? (2 * 62) : div;
517 div = (acder1 >> 8) & 0x3F;
518 //double the divider to avoid FP
519 div = (div == 0 || div == 1) ? 62 : div;
522 div = (acder1 >> 24) & 0x3F;
523 //double the divider to avoid FP
524 div = (div == 0 || div == 1) ? 62 : div;
527 diag_printf("Wrong clock: %d\n", clk);
534 void get_ref_clk(u32 *ap_unc_pat_ref, u32 *ap_ref_x2,
537 u32 ap_pat_ref_div_1, ap_pat_ref_div_2, ap_isel,
538 ascsr, adcr, acder2, clk_sel, ref_clk;
540 clk_sel = MXC_GET_FIELD(readl(PLL0_BASE_ADDR + PLL_DP_CTL), 2, 8);
541 ref_clk = fixed_mfd[clk_sel].ref_clk_hz;
543 ascsr = crm_ap_base[CRM_AP_ASCSR >> 2];
544 adcr = crm_ap_base[CRM_AP_ADCR >> 2];
545 acder2 = crm_ap_base[CRM_AP_ACDER2 >> 2];
547 ap_isel = ascsr & 0x1;
548 ap_pat_ref_div_1 = ((ascsr >> 2) & 0x1) + 1;
549 ap_pat_ref_div_2 = ((ascsr >> 15) & 0x1) + 1;
551 *ap_unc_pat_ref = ref_clk * (ap_isel + 1);
552 *ap_ref_x2 = (*ap_unc_pat_ref)/ ap_pat_ref_div_1;
553 *ap_ref = (*ap_ref_x2) / ap_pat_ref_div_2;
557 * This function returns the main clock value in Hz.
559 u32 get_main_clock(enum main_clocks clk)
561 u32 ret_val = 0, apsel, ap_clk_pre_dfs, acsr, ascsr, adcr, acder2;
562 u32 lfdf = 1, ap_ref_x2_clk, ap_ref_clk, usbsel, ap_unc_pat_ref;
564 acsr = crm_ap_base[CRM_AP_ACSR >> 2];
565 ascsr = crm_ap_base[CRM_AP_ASCSR >> 2];
566 adcr = crm_ap_base[CRM_AP_ADCR >> 2];
567 acder2 = crm_ap_base[CRM_AP_ACDER2 >> 2];
569 get_ref_clk(&ap_unc_pat_ref, &ap_ref_x2_clk, &ap_ref_clk);
571 if ((acsr & 0x1) == 0) {
572 // inverted pat_ref is selected
573 ap_clk_pre_dfs = ap_ref_clk;
575 // Now AP domain runs off the pll
576 apsel = (ascsr >> 3) & 0x3;
577 ap_clk_pre_dfs = pll_clock(apsel) / clock_divider(CPU_CLK);
582 if (((adcr & 0x2) == 0) && ((adcr & 0x20) != 0) && ((adcr & 0x80) == 0)) {
584 lfdf = 2 ^ ((adcr >> 8) & 0x3);
586 ret_val = ap_clk_pre_dfs / lfdf;
589 ret_val = ap_clk_pre_dfs / clock_divider(AHB_CLK);
592 ret_val = ap_clk_pre_dfs / clock_divider(IPG_CLK);
595 if ((acder2 & (1 << 20)) == 0) {
596 diag_printf("Warning: NFC clock is not enabled !!!\n");
598 ret_val = ap_clk_pre_dfs / (clock_divider(AHB_CLK) *
599 clock_divider(NFC_CLK));
603 if ((acder2 & (1 << 12)) == 0) {
604 diag_printf("Warning: USB clock is not enabled !!!\n");
606 if ((acsr & 0x1) == 0) {
607 // inverted pat_ref is selected
608 ret_val = ap_ref_clk / clock_divider(USB_CLK);
610 usbsel = (ascsr >> 13) & 0x3;
612 diag_printf("reserved source for USB input\n");
614 ret_val = pll_clock(usbsel) / clock_divider(USB_CLK);
626 * This function returns the peripheral clock value in Hz.
628 u32 get_peri_clock(enum peri_clocks clk)
630 u32 apra, ascsr, acder1, acder2, ap_unc_pat_ref,
631 ap_ref_x2_clk, ap_ref_clk, ret_val = 0, sel;
633 apra = crm_ap_base[CRM_AP_APRA >> 2];
634 acder1 = crm_ap_base[CRM_AP_ACDER1 >> 2];
635 acder2 = crm_ap_base[CRM_AP_ACDER2 >> 2];
636 ascsr = crm_ap_base[CRM_AP_ASCSR >> 2];
638 get_ref_clk(&ap_unc_pat_ref, &ap_ref_x2_clk, &ap_ref_clk);
642 if ((apra & 0x1) == 0) {
645 ret_val = ap_unc_pat_ref / clock_peri_divider(UART1_BAUD);
648 if ((apra & 0x100) == 0) {
651 ret_val = ap_unc_pat_ref / clock_peri_divider(UART2_BAUD);
654 if ((apra & 0x10000) == 0) {
657 ret_val = ap_unc_pat_ref / clock_peri_divider(UART3_BAUD);
660 if ((acder1 & (1 << 6)) == 0) {
664 sel = (ascsr >> 5) & 0x3;
665 // Don't forget to double the divider
666 ret_val = (2 * pll_clock(sel)) / clock_peri_divider(SSI1_BAUD);
669 if ((acder1 & (1 << 14)) == 0) {
673 sel = (ascsr >> 7) & 0x3;
674 // Don't forget to double the divider
675 ret_val = (2 *pll_clock(sel)) / clock_peri_divider(SSI2_BAUD);
678 if ((acder1 & (1 << 30)) == 0) {
682 sel = (ascsr >> 11) & 0x3;
683 // Don't forget to double the divider
684 ret_val = (2 * pll_clock(sel)) / (clock_peri_divider(CSI_BAUD));
692 "Select clock source for CKOH (J9 on CPU daughter card)",
693 " Default is 1/10 of ARM core\n\
694 <0> - display current ckoh selection \n\
695 <1> - ap_uncorrected_pat_ref_clk \n\
696 <2> - ungated_ap_clk (ARM Core in normal case) \n\
697 <3> - ungated_ap_ahb_clk (AHB) \n\
698 <4> - ungated_ap_pclk (IPG) \n\
700 <6> - ap_perclk (baud clock) \n\
701 <7> - ap_ckil_clk (sync) \n\
702 <8> - ap_pat_ref_clk (ungated sync) \n\
703 <<The following only valid for Rev2.0 silicon and above>> \n\
704 <9> - crm_ap_nfc_clk \n\
705 <10> - ap_async_pat_ref_clk for EL1T and MQSPI \n\
706 <11> - ap_sdhc1_perclk \n\
707 <12> - ap_ahb_div2_clk (for SAHARA) \n\
708 <13> - ipu_lpmc_hsp_clk\n",
712 static u8* div_str[] = {
731 static u8* ckoh_name[] ={
733 "ap_uncorrected_pat_ref_clk",
734 "ungated_ap_clk (ARM Core in normal case)",
735 "ungated_ap_ahb_clk (AHB)",
736 "ungated_ap_pclk (IPG)",
738 "ap_perclk (baud clock)",
739 "ap_ckil_clk (sync)",
740 "ap_pat_ref_clk (ungated sync)",
742 "ap_async_pat_ref_clk for EL1T and MQSPI",
744 "ap_ahb_div2_clk (for SAHARA)",
748 #define CKOH_MAX_INDEX (sizeof(ckoh_name) / sizeof(u8*))
749 #define CKOH_DIV 6 // default divide by 10
751 extern u32 system_rev;
753 static void ckoh(int argc,char *argv[])
755 u32 action = 0, val, new_val, div = 0x8, i;
757 if (!scan_opts(argc, argv, 1, 0, 0, (void*) &action,
758 OPTION_ARG_TYPE_NUM, "action"))
761 if (action >= CKOH_MAX_INDEX ||
762 (((system_rev >> 4) & 0xF) == CHIP_REV_1_0 && action > 8)) {
763 diag_printf("%d is not supported\n\n", action);
767 val = readl(CRM_AP_BASE_ADDR + CRM_AP_ACR);
770 // set CKOHDIV to be 6 for dividing by 10
771 if (action == 2 || action == 3)
774 // clear CKOHS-HIGH, CKOHD, CHOHS, CKOHDIV bits and
775 new_val = (val & (~(1 << 18 | 0xFF00))) | (div << 8);
777 new_val |= (1 << 18) | ((action & 7) << 12);
779 new_val |= action << 12;
781 writel(new_val, CRM_AP_BASE_ADDR + CRM_AP_ACR);
782 diag_printf("\nSet ckoh to ");
785 val = readl(CRM_AP_BASE_ADDR + CRM_AP_ACR);
786 /* locate the index in the name table */
787 new_val = ((val >> 15) & 8) | ((val >> 12) & 7);
788 i = (val >> 8) & 0xF;
789 diag_printf("%s%s\n", div_str[i], ckoh_name[new_val + 1]);
790 diag_printf("ACR register[0x%x]=0x%x\n\n",
791 (CRM_AP_BASE_ADDR + CRM_AP_ACR), val);
795 "Select clock source for CKO (J10 on EVB CPU card)",
797 <0> - display current cko selection\n\
799 <2> - ap_pat_ref_clk (ungated sync) \n\
800 <3> - ap_ref_x2_clk \n\
806 <<The following only valid for Rev2.0 silicon and above>> \n\
807 <9> - dfm_ckil_multiply_clk \n\
808 <10> - ap_sdhc2_perclk \n\
809 <11> - ap_uart3_per_clk \n",
813 static u8* cko_name[] ={
816 "ap_pat_ref_clk (ungated sync)",
823 "dfm_ckil_multiply_clk",
828 #define CKO_MAX_INDEX (sizeof(cko_name) / sizeof(u8*))
830 static void ckol(int argc,char *argv[])
832 u32 action = 0, val, new_val, t;
834 if (!scan_opts(argc, argv, 1, 0, 0, (void*) &action,
835 OPTION_ARG_TYPE_NUM, "action"))
838 if (action >= CKO_MAX_INDEX ||
839 (((system_rev >> 4) & 0xF) == CHIP_REV_1_0 && action > 6) ||
840 (action >= 7 && action <= 8)) {
841 diag_printf("%d is not supported\n\n", action);
845 val = readl(CRM_AP_BASE_ADDR + CRM_AP_ACR);
848 // turn on these clocks
851 t = readl(CRM_AP_BASE_ADDR + CRM_AP_ACDER1);
852 writel(t | (1 << 6), CRM_AP_BASE_ADDR + CRM_AP_ACDER1);
855 t = readl(CRM_AP_BASE_ADDR + CRM_AP_ACDER1);
856 writel(t | (1 << 14), CRM_AP_BASE_ADDR + CRM_AP_ACDER1);
859 t = readl(CRM_AP_BASE_ADDR + CRM_AP_ACDER1);
860 writel(t | (1 << 30), CRM_AP_BASE_ADDR + CRM_AP_ACDER1);
865 /* clear CKOS-HIGH, CKOD, CHOS bits and */
866 new_val = val & (~((1 << 16) | 0xF0));
868 new_val |= (1 << 16) | ((action & 7) << 4);
870 new_val |= action << 4;
872 writel(new_val, CRM_AP_BASE_ADDR + CRM_AP_ACR);
873 diag_printf("\nSet cko to ");
876 val = readl(CRM_AP_BASE_ADDR + CRM_AP_ACR);
877 /* locate the index in the name table */
878 new_val = ((val >> 13) & 8) | ((val >> 4) & 7);
880 diag_printf("%s\nACR register[0x%x]=0x%x\n\n", cko_name[new_val + 1],
881 (CRM_AP_BASE_ADDR + CRM_AP_ACR), val);
886 * This command is added for some simple testing only. It turns on/off
887 * L2 cache regardless of L1 cache state. The side effect of this is
888 * when doing any flash operations such as "fis init", the L2
889 * will be turned back on along with L1 caches even though it is off
890 * by using this command.
898 void do_L2_caches(int argc, char *argv[])
904 if (strcasecmp(argv[1], "on") == 0) {
905 HAL_DISABLE_INTERRUPTS(oldints);
907 HAL_RESTORE_INTERRUPTS(oldints);
908 } else if (strcasecmp(argv[1], "off") == 0) {
909 HAL_DISABLE_INTERRUPTS(oldints);
910 HAL_CLEAN_INVALIDATE_L2();
912 HAL_RESTORE_INTERRUPTS(oldints);
914 diag_printf("Invalid L2 cache mode: %s\n", argv[1]);
917 HAL_L2CACHE_IS_ENABLED(L2cache_on);
918 diag_printf("L2 cache: %s\n", L2cache_on?"On":"Off");
921 #endif //L2CC_ENABLED
923 #define IIM_ERR_SHIFT 8
924 #define POLL_FUSE_PRGD (IIM_STAT_PRGD | (IIM_ERR_PRGE << IIM_ERR_SHIFT))
925 #define POLL_FUSE_SNSD (IIM_STAT_SNSD | (IIM_ERR_SNSE << IIM_ERR_SHIFT))
927 static void fuse_op_start(void)
929 /* Do not generate interrupt */
930 writel(0, IIM_BASE_ADDR + IIM_STATM_OFF);
931 // clear the status bits and error bits
932 writel(0x3, IIM_BASE_ADDR + IIM_STAT_OFF);
933 writel(0xFE, IIM_BASE_ADDR + IIM_ERR_OFF);
937 * The action should be either:
942 static int poll_fuse_op_done(int action)
947 if (action != POLL_FUSE_PRGD && action != POLL_FUSE_SNSD) {
948 diag_printf("%s(%d) invalid operation\n", __FUNCTION__, action);
952 /* Poll busy bit till it is NOT set */
953 while ((readl(IIM_BASE_ADDR + IIM_STAT_OFF) & IIM_STAT_BUSY) != 0 ) {
956 /* Test for successful write */
957 status = readl(IIM_BASE_ADDR + IIM_STAT_OFF);
958 error = readl(IIM_BASE_ADDR + IIM_ERR_OFF);
960 if ((status & action) != 0 && (error & (action >> IIM_ERR_SHIFT)) == 0) {
962 diag_printf("Even though the operation seems successful...\n");
963 diag_printf("There are some error(s) at addr=0x%x: 0x%x\n",
964 (IIM_BASE_ADDR + IIM_ERR_OFF), error);
968 diag_printf("%s(%d) failed\n", __FUNCTION__, action);
969 diag_printf("status address=0x%x, value=0x%x\n",
970 (IIM_BASE_ADDR + IIM_STAT_OFF), status);
971 diag_printf("There are some error(s) at addr=0x%x: 0x%x\n",
972 (IIM_BASE_ADDR + IIM_ERR_OFF), error);
976 static void sense_fuse(int bank, int row, int bit)
978 int addr, addr_l, addr_h, reg_addr;
982 addr = ((bank << 11) | (row << 3) | (bit & 0x7));
983 /* Set IIM Program Upper Address */
984 addr_h = (addr >> 8) & 0x000000FF;
985 /* Set IIM Program Lower Address */
986 addr_l = (addr & 0x000000FF);
988 #ifdef IIM_FUSE_DEBUG
989 diag_printf("%s: addr_h=0x%x, addr_l=0x%x\n",
990 __FUNCTION__, addr_h, addr_l);
992 writel(addr_h, IIM_BASE_ADDR + IIM_UA_OFF);
993 writel(addr_l, IIM_BASE_ADDR + IIM_LA_OFF);
995 writel(0x8, IIM_BASE_ADDR + IIM_FCTL_OFF);
996 if (poll_fuse_op_done(POLL_FUSE_SNSD) != 0) {
997 diag_printf("%s(bank: %d, row: %d, bit: %d failed\n",
998 __FUNCTION__, bank, row, bit);
1000 reg_addr = IIM_BASE_ADDR + IIM_SDAT_OFF;
1001 diag_printf("fuses at (bank:%d, row:%d) = 0x%x\n", bank, row, readl(reg_addr));
1004 void do_fuse_read(int argc, char *argv[])
1009 diag_printf("Useage: fuse_read <bank> <row>\n");
1011 } else if (argc == 3) {
1012 if (!parse_num(*(&argv[1]), (unsigned long *)&bank, &argv[1], " ")) {
1013 diag_printf("Error: Invalid parameter\n");
1016 if (!parse_num(*(&argv[2]), (unsigned long *)&row, &argv[2], " ")) {
1017 diag_printf("Error: Invalid parameter\n");
1021 diag_printf("Read fuse at bank:%d row:%d\n", bank, row);
1022 sense_fuse(bank, row, 0);
1025 diag_printf("Passing in wrong arguments: %d\n", argc);
1026 diag_printf("Useage: fuse_read <bank> <row>\n");
1030 /* Blow fuses based on the bank, row and bit positions (all 0-based)
1032 static int fuse_blow(int bank,int row,int bit)
1034 int addr, addr_l, addr_h, ret = -1;
1038 /* Disable IIM Program Protect */
1039 writel(0xAA, IIM_BASE_ADDR + IIM_PREG_P_OFF);
1041 addr = ((bank << 11) | (row << 3) | (bit & 0x7));
1042 /* Set IIM Program Upper Address */
1043 addr_h = (addr >> 8) & 0x000000FF;
1044 /* Set IIM Program Lower Address */
1045 addr_l = (addr & 0x000000FF);
1047 #ifdef IIM_FUSE_DEBUG
1048 diag_printf("blowing addr_h=0x%x, addr_l=0x%x\n", addr_h, addr_l);
1051 writel(addr_h, IIM_BASE_ADDR + IIM_UA_OFF);
1052 writel(addr_l, IIM_BASE_ADDR + IIM_LA_OFF);
1053 /* Start Programming */
1054 writel(0x31, IIM_BASE_ADDR + IIM_FCTL_OFF);
1055 if (poll_fuse_op_done(POLL_FUSE_PRGD) == 0) {
1059 /* Enable IIM Program Protect */
1060 writel(0x0, IIM_BASE_ADDR + IIM_PREG_P_OFF);
1065 * This command is added for burning IIM fuses
1067 RedBoot_cmd("fuse_read",
1073 RedBoot_cmd("fuse_blow",
1075 "<bank> <row> <value>",
1079 #define INIT_STRING "12345678"
1080 static char ready_to_blow[] = INIT_STRING;
1082 void quick_itoa(u32 num, char *a)
1085 for (i = 0; i <= 7; i++) {
1086 j = (num >> (4 * i)) & 0xF;
1087 k = (j < 10) ? '0' : ('a' - 0xa);
1092 void do_fuse_blow(int argc, char *argv[])
1094 int bank, row, value, i;
1097 diag_printf("It is too dangeous for you to use this command.\n");
1099 } else if (argc == 2) {
1100 if (strcasecmp(argv[1], "nandboot") == 0) {
1101 quick_itoa(readl(EPIT_BASE_ADDR + EPITCNR), ready_to_blow);
1102 diag_printf("%s\n", ready_to_blow);
1105 } else if (argc == 3) {
1106 if (strcasecmp(argv[1], "nandboot") == 0 &&
1107 strcasecmp(argv[2], ready_to_blow) == 0) {
1108 #if defined(CYGPKG_HAL_ARM_MXC91131) || defined(CYGPKG_HAL_ARM_MX21) || defined(CYGPKG_HAL_ARM_MX27) || defined(CYGPKG_HAL_ARM_MX31)
1109 diag_printf("No need to blow any fuses for NAND boot on this platform\n\n");
1111 diag_printf("Ready to burn NAND boot fuses\n");
1112 if (fuse_blow(0, 16, 1) != 0 || fuse_blow(0, 16, 7) != 0) {
1113 diag_printf("NAND BOOT fuse blown failed miserably ...\n");
1115 diag_printf("NAND BOOT fuse blown successfully ...\n");
1118 diag_printf("Not ready: %s, %s\n", argv[1], argv[2]);
1121 } else if (argc == 4) {
1122 if (!parse_num(*(&argv[1]), (unsigned long *)&bank, &argv[1], " ")) {
1123 diag_printf("Error: Invalid parameter\n");
1126 if (!parse_num(*(&argv[2]), (unsigned long *)&row, &argv[2], " ")) {
1127 diag_printf("Error: Invalid parameter\n");
1130 if (!parse_num(*(&argv[3]), (unsigned long *)&value, &argv[3], " ")) {
1131 diag_printf("Error: Invalid parameter\n");
1135 diag_printf("Blowing fuse at bank:%d row:%d value:%d\n",
1137 for (i = 0; i < 8; i++) {
1138 if (((value >> i) & 0x1) == 0) {
1141 if (fuse_blow(bank, row, i) != 0) {
1142 diag_printf("fuse_blow(bank: %d, row: %d, bit: %d failed\n",
1145 diag_printf("fuse_blow(bank: %d, row: %d, bit: %d successful\n",
1149 sense_fuse(bank, row, 0);
1152 diag_printf("Passing in wrong arguments: %d\n", argc);
1154 /* Reset to default string */
1155 strcpy(ready_to_blow, INIT_STRING);;
1158 /* precondition: m>0 and n>0. Let g=gcd(m,n). */
1159 int gcd(int m, int n)
1163 if(n > m) {t = m; m = n; n = t;} /* swap */