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 4 //should be enough even though max is 12
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 399] -> Core=399 AHB=133 IPG=66.5\n\
117 [clock 399:6] -> Core=399 AHB=66.5(Core/8) IPG=66.5\n\
118 [clock 399:6:2] -> Core=532 AHB=66.5(Core/8) IPG=33.25(AHB/2)\n",
123 * This is to calculate various parameters based on reference clock and
124 * targeted clock based on the equation:
125 * t_clk = 2*ref_freq*(mfi + mfn/(mfd+1))/(pd+1)
126 * This calculation is based on a fixed MFD value for simplicity.
128 * @param ref reference clock freq in Hz
129 * @param target targeted clock in Hz
130 * @param p_pd calculated pd value (pd value from register + 1) upon return
131 * @param p_mfi calculated actual mfi value upon return
132 * @param p_mfn calculated actual mfn value upon return
133 * @param p_mfd fixed mfd value (mfd value from register + 1) upon return
135 * @return 0 if successful; non-zero otherwise.
137 int calc_pll_params(u32 ref, u32 target, struct pll_param *pll)
139 u64 pd, mfi = 1, mfn, mfd, n_target = target, n_ref = ref, i;
141 // make sure targeted freq is in the valid range. Otherwise the
142 // following calculation might be wrong!!!
143 if (n_target < PLL_FREQ_MIN(ref) || n_target > PLL_FREQ_MAX(ref))
144 return ERR_WRONG_CLK;
146 if (i == REF_IN_CLK_NUM)
147 return ERR_WRONG_CLK;
148 if (fixed_mfd[i].ref_clk_hz == ref) {
149 mfd = fixed_mfd[i].mfd;
153 // use n_target and n_ref to avoid overflow
154 for (pd = 1; pd <= PLL_PD_MAX; pd++) {
155 mfi = (n_target * pd) / (2 * n_ref);
156 if (mfi > PLL_MFI_MAX)
162 // Now got pd and mfi already
163 mfn = (((n_target * pd) / 2 - n_ref * mfi) * mfd) / n_ref;
164 #ifdef CMD_CLOCK_DEBUG
165 diag_printf("%d: ref=%d, target=%d, pd=%d, mfi=%d,mfn=%d, mfd=%d\n",
166 __LINE__, ref, (u32)n_target, (u32)pd, (u32)mfi, (u32)mfn, (u32)mfd);
173 pll->mfn = (u32)(mfn / i);
174 pll->mfd = (u32)(mfd / i);
179 * This function assumes the expected core clock has to be changed by
180 * modifying the PLL. This is NOT true always but for most of the times,
181 * it is. So it assumes the PLL output freq is the same as the expected
182 * core clock (arm_div=1) unless the core clock is less than PLL_FREQ_MIN.
183 * In the latter case, it will try to increase the arm_div value until
184 * (arm_div*core_clk) is greater than PLL_FREQ_MIN. It then makes call to
185 * calc_pll_params() and obtains the values of PD, MFI,MFN, MFD based
186 * on the targeted PLL and reference input clock to the PLL. Lastly,
187 * it sets the register based on these values along with the dividers.
188 * Note 1) There is no value checking for the passed-in divider values
189 * so the caller has to make sure those values are sensible.
190 * 2) Also adjust the NFC divider such that the NFC clock doesn't
191 * exceed NFC_CLK_MAX.
192 * 3) This function should not have allowed diag_printf() calls since
193 * the serial driver has been stoped. But leave then here to allow
194 * easy debugging by NOT calling the cyg_hal_plf_serial_stop().
195 * 4) The IPG divider doesn't go through AHB divider
197 * @param ref pll input reference clock (32KHz or 26MHz)
198 * @param core_clk core clock in Hz
199 * @param ahb_div ahb divider to divide the core clock to get ahb clock
200 * (ahb_div - 1) needs to be set in the register
201 * @param ipg_div ipg divider to divide the core clock to get ipg clock
202 * (ipg_div - 1) needs to be set in the register
203 # @return 0 if successful; non-zero otherwise
205 int configure_clock(u32 ref, u32 core_clk, u32 ahb_div, u32 ipg_div)
207 u32 pll, arm_div = 1, nfc_div, acdr, acder2;
208 struct pll_param pll_param;
211 // assume pll default to core clock first
213 // when core_clk >= PLL_FREQ_MIN, the arm_div can be 1.
214 // Otherwise, need to calculate arm_div value below and adjust the targeted pll
215 if (core_clk < PLL_FREQ_MIN(ref)) {
216 for (arm_div = 1; arm_div <= ARM_DIV_MAX; arm_div++) {
217 if ((core_clk * arm_div) > PLL_FREQ_MIN(ref)) {
221 if (arm_div == (ARM_DIV_MAX + 1)) {
222 diag_printf("can't make arm_div=%d\n", arm_div);
223 return ERR_NO_ARM_DIV;
225 pll = core_clk * arm_div;
228 // get nfc_div - make sure optimal NFC clock but less than NFC_CLK_MAX
229 for (nfc_div = 1; nfc_div <= NFC_DIV_MAX; nfc_div++) {
230 if ((pll / (ahb_div * nfc_div)) <= NFC_CLK_MAX) {
235 // pll is now the targeted pll output. Use it along with ref input clock
236 // to get pd, mfi, mfn, mfd
237 if ((ret = calc_pll_params(ref, pll, &pll_param)) != 0) {
238 diag_printf("can't find pll parameters: %d\n", ret);
241 #ifdef CMD_CLOCK_DEBUG
242 diag_printf("ref=%d, pll=%d, pd=%d, mfi=%d,mfn=%d, mfd=%d\n",
243 ref, pll, pll_param.pd, pll_param.mfi, pll_param.mfn, pll_param.mfd);
245 acdr = ((arm_div - 1) << 8) |
246 ((ahb_div - 1) << 4) |
249 acder2 = (readl(CRM_AP_BASE_ADDR + CRM_AP_ACDER) & 0xFFF0FFFF) |
250 ((nfc_div - 1) << 16);
252 // switch to ap_ref_clk
253 writel(readl(CRM_AP_BASE_ADDR + CRM_AP_ACSR) & (~0x1),
254 CRM_AP_BASE_ADDR + CRM_AP_ACSR);
256 // change the dividers
257 writel(acdr, CRM_AP_BASE_ADDR + CRM_AP_ACDR);
258 writel(acder2, CRM_AP_BASE_ADDR + CRM_AP_ACDER);
260 // adjust pll settings
261 writel(((pll_param.pd - 1) << 0) | (pll_param.mfi << 4),
262 PLL0_BASE_ADDR + PLL_DP_OP);
263 writel(pll_param.mfn, PLL0_BASE_ADDR + PLL_DP_MFN);
264 writel(pll_param.mfd - 1, PLL0_BASE_ADDR + PLL_DP_MFD);
265 writel(((pll_param.pd - 1) << 0) | (pll_param.mfi << 4),
266 PLL0_BASE_ADDR + PLL_DP_HFS_OP);
267 writel(pll_param.mfn, PLL0_BASE_ADDR + PLL_DP_HFS_MFN);
268 writel(pll_param.mfd - 1, PLL0_BASE_ADDR + PLL_DP_HFS_MFD);
270 // switch back to pll
271 writel(readl(CRM_AP_BASE_ADDR + CRM_AP_ACSR) | 0x1,
272 CRM_AP_BASE_ADDR + CRM_AP_ACSR);
277 static void clock_setup(int argc,char *argv[])
279 u32 i, core_clk, ipg_div, data[3], uart1_baud, ssi1_baud;
280 u32 csi_baud, ahb_div, ahb_clk, ipg_clk, clk_sel, ref_clk;
285 for (i = 0; i < 3; i++) {
287 if (!parse_num(*(&argv[1]), &temp, &argv[1], ":")) {
288 diag_printf("Error: Invalid parameter\n");
294 core_clk = data[0] * SZ_DEC_1M;
295 ahb_div = data[1]; // actual register field + 1
296 ipg_div = data[2]; // actual register field + 1
298 // since only support set clock for the AP domain, get ref input clock
299 // for the AP domain.
300 clk_sel = MXC_GET_FIELD(readl(PLL0_BASE_ADDR + PLL_DP_CTL), 2, 8);
301 ref_clk = fixed_mfd[clk_sel].ref_clk_hz;
303 if (core_clk < (PLL_FREQ_MIN(ref_clk) / ARM_DIV_MAX) ||
304 core_clk > PLL_FREQ_MAX(ref_clk)) {
305 diag_printf("Targeted core clock should be within [%d - %d]\n",
306 PLL_FREQ_MIN(ref_clk) / ARM_DIV_MAX,
307 PLL_FREQ_MAX(ref_clk));
311 // find the ahb divider
312 if (ahb_div > AHB_DIV_MAX) {
313 diag_printf("Invalid AHB divider: %d. Maximum value is %d\n",
314 ahb_div, AHB_DIV_MAX);
318 // no HCLK divider specified
319 for (ahb_div = 1; ; ahb_div++) {
320 if ((core_clk / ahb_div) <= AHB_CLK_MAX)
324 if (ahb_div > AHB_DIV_MAX || (core_clk / ahb_div) > AHB_CLK_MAX) {
325 diag_printf("Can't make AHB=%d since max=%d\n",
326 core_clk / ahb_div, AHB_CLK_MAX);
330 // find the ipg divider
331 ahb_clk = core_clk / ahb_div;
333 ipg_div++; // At least =1
334 if (ahb_clk > IPG_CLK_MAX)
335 ipg_div++; // Make it =2
337 ipg_clk = ahb_clk / ipg_div;
338 if (ipg_div > IPG_DIV_MAX || ipg_clk > IPG_CLK_MAX) {
339 if (ipg_div > IPG_DIV_MAX)
340 diag_printf("Invalid IPG divider: %d. Max is: %d\n",
341 ipg_div / ahb_div, IPG_DIV_MAX / ahb_div);
343 diag_printf("Can't make IPG=%dHz since max=%dHz\n",
344 ipg_clk, IPG_CLK_MAX);
348 diag_printf("Trying to set core=%d ahb=%d ipg=%d...\n",
349 core_clk, ahb_clk, ipg_clk);
351 // stop the serial to be ready to adjust the clock
352 hal_delay_us(100000);
353 cyg_hal_plf_serial_stop();
355 ret = configure_clock(ref_clk, core_clk, ahb_div, ipg_div);
356 // restart the serial driver
357 cyg_hal_plf_serial_init();
358 hal_delay_us(100000);
361 diag_printf("Failed to setup clock: %d\n", ret);
364 diag_printf("\n<<<New clock setting>>>\n");
366 // Now printing clocks
368 diag_printf("\nMCUPLL\t\tUSBPLL\t\tDSPPLL\n");
369 diag_printf("========================================\n");
370 diag_printf("%-16d%-16d%-16d\n\n", pll_clock(PLL0), pll_clock(PLL2),
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 uart1_baud = get_peri_clock(UART1_BAUD);
383 ssi1_baud = get_peri_clock(SSI1_BAUD);
384 csi_baud = get_peri_clock(CSI_BAUD);
386 diag_printf("UART1/2\t\tSSI1\t\tCSI\n");
387 diag_printf("===========================================");
388 diag_printf("=============================\n");
390 (uart1_baud != NOT_ON_VAL) ? diag_printf("%-16d", uart1_baud) :
391 diag_printf("%-16s", "OFF");
392 (ssi1_baud != NOT_ON_VAL) ? diag_printf("%-16d", ssi1_baud) :
393 diag_printf("%-16s", "OFF");
394 (csi_baud != NOT_ON_VAL) ? diag_printf("%-16d", csi_baud ) :
395 diag_printf("%-16s", "OFF");
400 * This function returns the PLL output value in Hz based on pll.
402 u32 pll_clock(enum plls pll)
404 u64 mfi, mfn, mfd, pdf, ref_clk, pll_out, sign;
405 u64 dp_op, dp_mfd, dp_mfn, clk_sel;
407 clk_sel = MXC_GET_FIELD(pll_base[pll][PLL_DP_CTL >> 2], 2, 8);
408 ref_clk = fixed_mfd[clk_sel].ref_clk_hz;
410 if ((pll_base[pll][PLL_DP_CTL >> 2] & 0x80) == 0) {
411 dp_op = pll_base[pll][PLL_DP_OP >> 2];
412 dp_mfd = pll_base[pll][PLL_DP_MFD >> 2];
413 dp_mfn = pll_base[pll][PLL_DP_MFN >> 2];
415 dp_op = pll_base[pll][PLL_DP_HFS_OP >> 2];
416 dp_mfd = pll_base[pll][PLL_DP_HFS_MFD >> 2];
417 dp_mfn = pll_base[pll][PLL_DP_HFS_MFN >> 2];
420 mfi = (dp_op >> 4) & 0xF;
421 mfi = (mfi <= 5) ? 5: mfi;
422 mfd = dp_mfd & 0x07FFFFFF;
423 mfn = dp_mfn & 0x07FFFFFF;
425 sign = (mfn < 0x4000000) ? 0: 1;
426 mfn = (mfn <= 0x4000000) ? mfn: (0x8000000 - mfn);
429 pll_out = (2 * ref_clk * mfi + ((2 * ref_clk * mfn) / (mfd + 1))) /
432 pll_out = (2 * ref_clk * mfi - ((2 * ref_clk * mfn) / (mfd + 1))) /
439 const u32 CRM_SMALL_DIV[] = {2, 3, 4, 5, 6, 8, 10, 12};
442 * This function returns the main clock dividers.
444 u32 clock_divider(enum main_clocks clk)
449 acdr = crm_ap_base[CRM_AP_ACDR >> 2];
450 acder = crm_ap_base[CRM_AP_ACDER >> 2];
454 div = (acdr >> 8) & 0x7;
455 div = (div > 3) ? 1 : (div + 1);
458 div = ((acdr >> 4) & 0x7) + 1;
461 div = ((acdr >> 0) & 0x3) + 1;
464 div = ((acder >> 16) & 0xF) + 1;
467 div = (acder >> 0) & 0xF;
468 div = (div > 7) ? 1 : (CRM_SMALL_DIV[div]);
471 diag_printf("Wrong clock: %d\n", clk);
479 * This function returns the peripheral clock dividers.
481 u32 clock_peri_divider(enum peri_clocks clk)
486 acder = crm_ap_base[CRM_AP_ACDER >> 2];
490 div = (acder >> 8) & 0x3F;
491 //double the divider to avoid FP
492 div = (2 * ((div >> 1) & 0x1F)) + (div & 0x1);
493 div = (div == 0 || div == 1) ? (2 * 62) : div;
496 div = (acder >> 24) & 0x3F;
497 //double the divider to avoid FP
498 div = (2 * ((div >> 1) & 0x1F)) + (div & 0x1);
499 div = (div == 0 || div == 1) ? (2 * 62) : div;
502 diag_printf("Wrong clock: %d\n", clk);
509 void get_ref_clk(u32 *ap_unc_pat_ref, u32 *ap_ref_x2,
512 u32 ap_pat_ref_div_1, ascsr, adcr, clk_sel, ref_clk;
514 clk_sel = MXC_GET_FIELD(readl(PLL0_BASE_ADDR + PLL_DP_CTL), 2, 8);
515 ref_clk = fixed_mfd[clk_sel].ref_clk_hz;
517 ascsr = crm_ap_base[CRM_AP_ASCSR >> 2];
519 ap_pat_ref_div_1 = ((ascsr >> 3) & 0x1) + 1;
521 *ap_ref_x2 = ref_clk;
522 *ap_ref = (*ap_ref_x2) / ap_pat_ref_div_1;
526 * This function returns the main clock value in Hz.
528 u32 get_main_clock(enum main_clocks clk)
530 u32 ret_val = 0, apsel, ap_clk_pre_dfs, acsr, acder;
531 u32 ap_ref_x2_clk, ap_ref_clk, usbsel, ap_unc_pat_ref;
533 acsr = crm_ap_base[CRM_AP_ACSR >> 2];
534 acder = crm_ap_base[CRM_AP_ACDER >> 2];
536 get_ref_clk(&ap_unc_pat_ref, &ap_ref_x2_clk, &ap_ref_clk);
538 if ((acsr & 0x1) == 0) {
539 // inverted pat_ref is selected
540 ap_clk_pre_dfs = ap_ref_clk;
543 ap_clk_pre_dfs = pll_clock(apsel);
548 ret_val = ap_clk_pre_dfs / clock_divider(CPU_CLK);
551 ret_val = ap_clk_pre_dfs / clock_divider(AHB_CLK);
555 ret_val = ap_clk_pre_dfs / (clock_divider(AHB_CLK) *
556 clock_divider(IPG_CLK));
559 if ((acder & (1 << 20)) == 0) {
560 diag_printf("Warning: NFC clock is not enabled !!!\n");
562 ret_val = ap_clk_pre_dfs / (clock_divider(AHB_CLK) *
563 clock_divider(NFC_CLK));
567 if ((acder & (1 << 4)) == 0) {
568 diag_printf("Warning: USB clock is not enabled !!!\n");
570 if ((acsr & 0x1) == 0) {
571 // inverted pat_ref is selected
572 ret_val = ap_ref_clk / clock_divider(USB_CLK);
575 ret_val = pll_clock(usbsel) / clock_divider(USB_CLK);
587 * This function returns the peripheral clock value in Hz.
589 u32 get_peri_clock(enum peri_clocks clk)
591 u32 ascsr, acder, ret_val = 0, sel;
593 acder = crm_ap_base[CRM_AP_ACDER >> 2];
594 ascsr = crm_ap_base[CRM_AP_ASCSR >> 2];
599 ret_val = get_main_clock(IPG_CLK);
602 if ((acder & (1 << 14)) == 0) {
608 // Don't forget to double the divider
609 ret_val = (2 * pll_clock(sel)) / (clock_peri_divider(SSI1_BAUD));
610 } else if (sel == 1) {
612 ret_val = (2 * pll_clock(sel)) / (clock_peri_divider(SSI1_BAUD));;
616 if ((acder & (1 << 30)) == 0) {
620 sel = (ascsr >> 1) & 0x3;
622 ret_val = (2 * pll_clock(sel)) / (clock_peri_divider(CSI_BAUD));
623 } else if (sel == 1) {
625 ret_val = (2 * pll_clock(sel)) / (clock_peri_divider(CSI_BAUD));;
626 } else if (sel == 2) {
627 ret_val = (2 * FREQ_CKIH_26M) / (clock_peri_divider(CSI_BAUD));
629 // Don't forget to double the divider
637 "Select clock source for CKOH (J9 on CPU daughter card)",
638 " Default is 1/10 of ARM core\n\
639 <0> - display current ckoh selection \n\
640 <1> - ap_uncorrected_pat_ref_clk \n\
641 <2> - ungated_ap_clk (ARM Core in normal case) \n\
642 <3> - ungated_ap_ahb_clk (AHB) \n\
643 <4> - ungated_ap_pclk (IPG) \n\
645 <6> - ap_perclk (baud clock) \n\
646 <7> - ap_ckil_clk (sync) \n\
647 <8> - ap_pat_ref_clk (ungated sync) \n\
648 <<The following only valid for Rev2.0 silicon and above>> \n\
649 <9> - crm_ap_nfc_clk \n\
650 <10> - ap_async_pat_ref_clk for EL1T and MQSPI \n\
651 <11> - ap_sdhc1_perclk \n\
652 <12> - ap_ahb_div2_clk (for SAHARA) \n\
653 <13> - ipu_lpmc_hsp_clk\n",
657 static u8* div_str[] = {
676 static u8* ckoh_name[] ={
678 "ap_uncorrected_pat_ref_clk",
679 "ungated_ap_clk (ARM Core in normal case)",
680 "ungated_ap_ahb_clk (AHB)",
681 "ungated_ap_pclk (IPG)",
683 "ap_perclk (baud clock)",
684 "ap_ckil_clk (sync)",
685 "ap_pat_ref_clk (ungated sync)",
687 "ap_async_pat_ref_clk for EL1T and MQSPI",
689 "ap_ahb_div2_clk (for SAHARA)",
693 #define CKOH_MAX_INDEX (sizeof(ckoh_name) / sizeof(u8*))
694 #define CKOH_DIV 6 // default divide by 10
696 extern u32 system_rev;
698 static void ckoh(int argc,char *argv[])
700 u32 action = 0, val, new_val, div = 0x8, i;
702 if (!scan_opts(argc, argv, 1, 0, 0, (void*) &action,
703 OPTION_ARG_TYPE_NUM, "action"))
706 if (action >= CKOH_MAX_INDEX ||
707 (system_rev == CHIP_REV_1_0 && action > 8)) {
708 diag_printf("%d is not supported\n\n", action);
712 val = readl(CRM_AP_BASE_ADDR + CRM_AP_ACR);
715 // set CKOHDIV to be 6 for dividing by 10
716 if (action == 2 || action == 3)
719 // clear CKOHS-HIGH, CKOHD, CHOHS, CKOHDIV bits and
720 new_val = (val & (~(1 << 18 | 0xFF00))) | (div << 8);
722 new_val |= (1 << 18) | ((action & 7) << 12);
724 new_val |= action << 12;
726 writel(new_val, CRM_AP_BASE_ADDR + CRM_AP_ACR);
727 diag_printf("\nSet ckoh to ");
730 val = readl(CRM_AP_BASE_ADDR + CRM_AP_ACR);
731 /* locate the index in the name table */
732 new_val = ((val >> 15) & 8) | ((val >> 12) & 7);
733 i = (val >> 8) & 0xF;
734 diag_printf("%s%s\n", div_str[i], ckoh_name[new_val + 1]);
735 diag_printf("ACR register[0x%x]=0x%x\n\n",
736 (CRM_AP_BASE_ADDR + CRM_AP_ACR), val);
740 "Select clock source for CKO (J10 on EVB CPU card)",
742 <0> - display current cko selection\n\
744 <2> - ap_pat_ref_clk (ungated sync) \n\
745 <3> - ap_ref_x2_clk \n\
750 <<The following only valid for Rev2.0 silicon and above>> \n\
751 <8> - dfm_ckil_multiply_clk \n\
752 <9> - ap_sdhc2_perclk \n",
756 static u8* cko_name[] ={
759 "ap_pat_ref_clk (ungated sync)",
765 "dfm_ckil_multiply_clk",
769 #define CKO_MAX_INDEX (sizeof(cko_name) / sizeof(u8*))
771 static void ckol(int argc,char *argv[])
773 u32 action = 0, val, new_val, t;
775 if (!scan_opts(argc, argv, 1, 0, 0, (void*) &action,
776 OPTION_ARG_TYPE_NUM, "action"))
779 if (action >= CKO_MAX_INDEX ||
780 (system_rev == CHIP_REV_1_0 && action > 6) ||
781 (action >= 7 && action <= 8)) {
782 diag_printf("%d is not supported\n\n", action);
786 val = readl(CRM_AP_BASE_ADDR + CRM_AP_ACR);
789 // turn on these clocks
792 t = readl(CRM_AP_BASE_ADDR + CRM_AP_ACDER1);
793 writel(t | (1 << 6), CRM_AP_BASE_ADDR + CRM_AP_ACDER1);
796 t = readl(CRM_AP_BASE_ADDR + CRM_AP_ACDER1);
797 writel(t | (1 << 14), CRM_AP_BASE_ADDR + CRM_AP_ACDER1);
800 t = readl(CRM_AP_BASE_ADDR + CRM_AP_ACDER1);
801 writel(t | (1 << 30), CRM_AP_BASE_ADDR + CRM_AP_ACDER1);
806 /* clear CKOS-HIGH, CKOD, CHOS bits and */
807 new_val = val & (~((1 << 16) | 0xF0));
809 new_val |= (1 << 16) | ((action & 7) << 4);
811 new_val |= action << 4;
813 writel(new_val, CRM_AP_BASE_ADDR + CRM_AP_ACR);
814 diag_printf("\nSet cko to ");
817 val = readl(CRM_AP_BASE_ADDR + CRM_AP_ACR);
818 /* locate the index in the name table */
819 new_val = ((val >> 13) & 8) | ((val >> 4) & 7);
821 diag_printf("%s\nACR register[0x%x]=0x%x\n\n", cko_name[new_val + 1],
822 (CRM_AP_BASE_ADDR + CRM_AP_ACR), val);
826 /* Comment out the fuse setting commands for now */
827 #define IIM_ERR_SHIFT 8
828 #define POLL_FUSE_PRGD (IIM_STAT_PRGD | (IIM_ERR_PRGE << IIM_ERR_SHIFT))
829 #define POLL_FUSE_SNSD (IIM_STAT_SNSD | (IIM_ERR_SNSE << IIM_ERR_SHIFT))
831 static void fuse_op_start(void)
833 /* Do not generate interrupt */
834 writel(0, IIM_BASE_ADDR + IIM_STATM_OFF);
835 // clear the status bits and error bits
836 writel(0x3, IIM_BASE_ADDR + IIM_STAT_OFF);
837 writel(0xFE, IIM_BASE_ADDR + IIM_ERR_OFF);
841 * The action should be either:
846 static int poll_fuse_op_done(int action)
851 if (action != POLL_FUSE_PRGD && action != POLL_FUSE_SNSD) {
852 diag_printf("%s(%d) invalid operation\n", __FUNCTION__, action);
856 /* Poll busy bit till it is NOT set */
857 while ((readl(IIM_BASE_ADDR + IIM_STAT_OFF) & IIM_STAT_BUSY) != 0 ) {
860 /* Test for successful write */
861 status = readl(IIM_BASE_ADDR + IIM_STAT_OFF);
862 error = readl(IIM_BASE_ADDR + IIM_ERR_OFF);
864 if ((status & action) != 0 && (error & (action >> IIM_ERR_SHIFT)) == 0) {
866 diag_printf("Even though the operation seems successful...\n");
867 diag_printf("There are some error(s) at addr=0x%x: 0x%x\n",
868 (IIM_BASE_ADDR + IIM_ERR_OFF), error);
872 diag_printf("%s(%d) failed\n", __FUNCTION__, action);
873 diag_printf("status address=0x%x, value=0x%x\n",
874 (IIM_BASE_ADDR + IIM_STAT_OFF), status);
875 diag_printf("There are some error(s) at addr=0x%x: 0x%x\n",
876 (IIM_BASE_ADDR + IIM_ERR_OFF), error);
880 static void sense_fuse(int bank, int row, int bit)
882 int addr, addr_l, addr_h, reg_addr;
886 addr = ((bank << 11) | (row << 3) | (bit & 0x7));
887 /* Set IIM Program Upper Address */
888 addr_h = (addr >> 8) & 0x000000FF;
889 /* Set IIM Program Lower Address */
890 addr_l = (addr & 0x000000FF);
892 #ifdef IIM_FUSE_DEBUG
893 diag_printf("%s: addr_h=0x%x, addr_l=0x%x\n",
894 __FUNCTION__, addr_h, addr_l);
896 writel(addr_h, IIM_BASE_ADDR + IIM_UA_OFF);
897 writel(addr_l, IIM_BASE_ADDR + IIM_LA_OFF);
899 writel(0x8, IIM_BASE_ADDR + IIM_FCTL_OFF);
900 if (poll_fuse_op_done(POLL_FUSE_SNSD) != 0) {
901 diag_printf("%s(bank: %d, row: %d, bit: %d failed\n",
902 __FUNCTION__, bank, row, bit);
904 reg_addr = IIM_BASE_ADDR + IIM_SDAT_OFF;
905 diag_printf("fuses at (bank:%d, row:%d) = 0x%x\n", bank, row, readl(reg_addr));
908 void do_fuse_read(int argc, char *argv[])
913 diag_printf("Useage: fuse_read <bank> <row>\n");
915 } else if (argc == 3) {
916 if (!parse_num(*(&argv[1]), (unsigned long *)&bank, &argv[1], " ")) {
917 diag_printf("Error: Invalid parameter\n");
920 if (!parse_num(*(&argv[2]), (unsigned long *)&row, &argv[2], " ")) {
921 diag_printf("Error: Invalid parameter\n");
925 diag_printf("Read fuse at bank:%d row:%d\n", bank, row);
926 sense_fuse(bank, row, 0);
929 diag_printf("Passing in wrong arguments: %d\n", argc);
930 diag_printf("Useage: fuse_read <bank> <row>\n");
934 /* Blow fuses based on the bank, row and bit positions (all 0-based)
936 static int fuse_blow(int bank,int row,int bit)
938 int addr, addr_l, addr_h, ret = -1;
942 /* Disable IIM Program Protect */
943 writel(0xAA, IIM_BASE_ADDR + IIM_PREG_P_OFF);
945 addr = ((bank << 11) | (row << 3) | (bit & 0x7));
946 /* Set IIM Program Upper Address */
947 addr_h = (addr >> 8) & 0x000000FF;
948 /* Set IIM Program Lower Address */
949 addr_l = (addr & 0x000000FF);
951 #ifdef IIM_FUSE_DEBUG
952 diag_printf("blowing addr_h=0x%x, addr_l=0x%x\n", addr_h, addr_l);
955 writel(addr_h, IIM_BASE_ADDR + IIM_UA_OFF);
956 writel(addr_l, IIM_BASE_ADDR + IIM_LA_OFF);
957 /* Start Programming */
958 writel(0x31, IIM_BASE_ADDR + IIM_FCTL_OFF);
959 if (poll_fuse_op_done(POLL_FUSE_PRGD) == 0) {
963 /* Enable IIM Program Protect */
964 writel(0x0, IIM_BASE_ADDR + IIM_PREG_P_OFF);
969 * This command is added for burning IIM fuses
971 RedBoot_cmd("fuse_read",
977 RedBoot_cmd("fuse_blow",
979 "<bank> <row> <value>",
983 #define INIT_STRING "12345678"
984 static char ready_to_blow[] = INIT_STRING;
986 void quick_itoa(u32 num, char *a)
989 for (i = 0; i <= 7; i++) {
990 j = (num >> (4 * i)) & 0xF;
991 k = (j < 10) ? '0' : ('a' - 0xa);
996 void do_fuse_blow(int argc, char *argv[])
998 int bank, row, value, i;
1001 diag_printf("It is too dangeous for you to use this command.\n");
1003 } else if (argc == 2) {
1004 if (strcasecmp(argv[1], "nandboot") == 0) {
1005 quick_itoa(readl(EPIT_BASE_ADDR + EPITCNR), ready_to_blow);
1006 diag_printf("%s\n", ready_to_blow);
1009 } else if (argc == 3) {
1010 if (strcasecmp(argv[1], "nandboot") == 0 &&
1011 strcasecmp(argv[2], ready_to_blow) == 0) {
1012 diag_printf("Ready to burn NAND boot fuses\n");
1013 if ((fuse_blow(0, 3, 2) != 0) || (fuse_blow(0, 4, 2) != 0) || (fuse_blow(0, 5, 1) != 0)) {
1014 //if (fuse_blow(0, 5, 1) != 0) {
1015 diag_printf("NAND BOOT fuse blown failed miserably ...\n");
1017 diag_printf("NAND BOOT fuse blown successfully ...\n");
1020 diag_printf("Not ready: %s, %s\n", argv[1], argv[2]);
1022 } else if (argc == 4) {
1023 if (!parse_num(*(&argv[1]), (unsigned long *)&bank, &argv[1], " ")) {
1024 diag_printf("Error: Invalid parameter\n");
1027 if (!parse_num(*(&argv[2]), (unsigned long *)&row, &argv[2], " ")) {
1028 diag_printf("Error: Invalid parameter\n");
1031 if (!parse_num(*(&argv[3]), (unsigned long *)&value, &argv[3], " ")) {
1032 diag_printf("Error: Invalid parameter\n");
1036 diag_printf("Blowing fuse at bank:%d row:%d value:%d\n",
1038 for (i = 0; i < 8; i++) {
1039 if (((value >> i) & 0x1) == 0) {
1042 if (fuse_blow(bank, row, i) != 0) {
1043 diag_printf("fuse_blow(bank: %d, row: %d, bit: %d failed\n",
1046 diag_printf("fuse_blow(bank: %d, row: %d, bit: %d successful\n",
1050 sense_fuse(bank, row, 0);
1053 diag_printf("Passing in wrong arguments: %d\n", argc);
1055 /* Reset to default string */
1056 strcpy(ready_to_blow, INIT_STRING);;
1059 /* precondition: m>0 and n>0. Let g=gcd(m,n). */
1060 int gcd(int m, int n)
1064 if(n > m) {t = m; m = n; n = t;} /* swap */