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>
46 #include CYGBLD_HAL_PLF_DEFS_H
48 #include "hab_super_root.h"
50 #ifndef FUSE_PROG_START
51 #define FUSE_PROG_START() CYG_EMPTY_STATEMENT
52 #define FUSE_PROG_DONE() CYG_EMPTY_STATEMENT
55 //#define IIM_FUSE_DEBUG
56 //#define CMD_CLOCK_DEBUG
57 #ifdef CMD_CLOCK_DEBUG
58 static int dbg_enable;
60 #define enable_dbg() \
72 #define enable_dbg() CYG_EMPTY_STATEMENT
73 #define dbg(fmt...) CYG_EMPTY_STATEMENT
76 static int gcd(int m, int n);
78 typedef unsigned long long u64;
79 typedef unsigned int u32;
80 typedef unsigned short u16;
81 typedef unsigned char u8;
83 #define SZ_DEC_1M 1000000
84 #define PLL_PD_MAX 16 //actual pd+1
85 #define PLL_MFI_MAX 15
100 #define PLL_FREQ_MAX(_ref_clk_) (4 * _ref_clk_ * PLL_MFI_MAX)
101 #define PLL_FREQ_MIN(_ref_clk_) ((2 * _ref_clk_ * (PLL_MFI_MIN - 1)) / PLL_PD_MAX)
102 #define MAX_DDR_CLK 400000000
103 #define AHB_CLK_MAX 133333333
104 #define IPG_CLK_MAX (AHB_CLK_MAX / 2)
105 #define NFC_CLK_MAX 25000000
106 // IPU-HSP clock is independent of the HCLK and can go up to 177MHz but requires
107 // higher voltage support. For simplicity, limit it to 133MHz
108 #define HSP_CLK_MAX 133333333
110 #define ERR_WRONG_CLK (-1)
111 #define ERR_NO_MFI (-2)
112 #define ERR_NO_MFN (-3)
113 #define ERR_NO_PD (-4)
114 #define ERR_NO_PRESC (-5)
115 #define ERR_NO_AHB_DIV (-6)
117 u32 pll_clock(enum plls pll);
118 u32 get_main_clock(enum main_clocks clk);
119 u32 get_peri_clock(enum peri_clocks clk);
121 static volatile u32 *pll_base[] =
123 ®32(PLL1_BASE_ADDR),
124 ®32(PLL2_BASE_ADDR),
125 ®32(PLL3_BASE_ADDR),
126 ®32(PLL4_BASE_ADDR),
129 static void clock_setup(int argc, char *argv[]);
132 "Setup/Display clock\nSyntax:",
133 "[<core clock in MHz> :<DDR clock in MHz>]\n\n"
135 " [clock] -> Show various clocks\n"
136 " [clock 665] -> Core=665\n"
137 " [clock 800:133] -> Core=800 DDR=133\n"
138 " [clock :166] -> Core=no change DDR=166\n",
143 * This is to calculate various parameters based on reference clock and
144 * targeted clock based on the equation:
145 * t_clk = 2*ref_freq*(mfi + mfn/(mfd+1))/(pd+1)
146 * This calculation is based on a fixed MFD value for simplicity.
148 * @param ref reference clock freq in Hz
149 * @param target targeted clock in Hz
150 * @param p_pd calculated pd value (pd value from register + 1) upon return
151 * @param p_mfi calculated actual mfi value upon return
152 * @param p_mfn calculated actual mfn value upon return
153 * @param p_mfd fixed mfd value (mfd value from register + 1) upon return
155 * @return 0 if successful; non-zero otherwise.
157 int calc_pll_params(u32 ref, u32 target, struct pll_param *pll)
159 int pd, mfi = 1, mfn, mfd, i;
160 u64 n_target = target, n_ref = ref;
162 // make sure targeted freq is in the valid range. Otherwise the
163 // following calculation might be wrong!!!
164 if (n_target < PLL_FREQ_MIN(ref) || n_target > PLL_FREQ_MAX(ref))
165 return ERR_WRONG_CLK;
169 // Use n_target and n_ref to avoid overflow
170 for (pd = 1; pd <= PLL_PD_MAX; pd++) {
171 mfi = (n_target * pd) / (4 * n_ref);
172 if (mfi > PLL_MFI_MAX) {
174 } else if (mfi < 5) {
179 // Now got pd and mfi already
180 mfn = (((n_target * pd) / 4 - n_ref * mfi) * mfd) / n_ref;
182 dbg("%d: ref=%d, target=%d, pd=%d, mfi=%d,mfn=%d, mfd=%d\n",
183 __LINE__, ref, target, pd, mfi, mfn, mfd);
196 * This function returns the low power audio clock.
201 u32 ccsr = readl(CCM_BASE_ADDR + CLKCTL_CCSR);
203 if (((ccsr >> 9) & 1) == 0) {
204 ret_val = FREQ_24MHZ;
206 ret_val = FREQ_32768HZ;
208 dbg("%s: CCSR[%08lx]=%08x freq=%u.%03uMHz\n", __FUNCTION__,
209 CCM_BASE_ADDR + CLKCTL_CCSR, ccsr, ret_val / 1000000, ret_val / 1000 % 1000);
214 * This function returns the periph_clk.
216 u32 get_periph_clk(void)
218 u32 ret_val, clk_sel;
220 u32 cbcdr = readl(CCM_BASE_ADDR + CLKCTL_CBCDR);
221 u32 cbcmr = readl(CCM_BASE_ADDR + CLKCTL_CBCMR);
223 if (!(cbcdr & (1 << 25))) {
224 ret_val = pll_clock(PLL2);
225 dbg("%s: CBCDR[%08lx]=%08x CBCMR[%08lx]=%08x freq=%u.%03uMHz\n", __FUNCTION__,
226 CCM_BASE_ADDR + CLKCTL_CBCDR, cbcdr,
227 CCM_BASE_ADDR + CLKCTL_CBCMR, cbcmr,
228 ret_val / 1000000, ret_val / 1000 % 1000);
230 clk_sel = (cbcmr >> 12) & 3;
232 ret_val = pll_clock(PLL1);
233 } else if (clk_sel == 1) {
234 ret_val = pll_clock(PLL3);
235 } else if (clk_sel == 2) {
236 ret_val = get_lp_apm();
238 diag_printf("Invalid CBCMR[CLK_SEL]: %d\n", clk_sel);
239 return ERR_WRONG_CLK;
241 dbg("%s: CBCDR[%08lx]=%08x CBCMR[%08lx]=%08x clk_sel=%d freq=%u.%03uMHz\n", __FUNCTION__,
242 CCM_BASE_ADDR + CLKCTL_CBCDR, cbcdr,
243 CCM_BASE_ADDR + CLKCTL_CBCMR, cbcmr,
244 clk_sel, ret_val / 1000000, ret_val / 1000 % 1000);
250 * This function assumes the expected core clock has to be changed by
251 * modifying the PLL. This is NOT true always but for most of the times,
252 * it is. So it assumes the PLL output freq is the same as the expected
253 * core clock (presc=1) unless the core clock is less than PLL_FREQ_MIN.
254 * In the latter case, it will try to increase the presc value until
255 * (presc*core_clk) is greater than PLL_FREQ_MIN. It then makes call to
256 * calc_pll_params() and obtains the values of PD, MFI,MFN, MFD based
257 * on the targeted PLL and reference input clock to the PLL. Lastly,
258 * it sets the register based on these values along with the dividers.
259 * Note 1) There is no value checking for the passed-in divider values
260 * so the caller has to make sure those values are sensible.
261 * 2) Also adjust the NFC divider such that the NFC clock doesn't
262 * exceed NFC_CLK_MAX.
263 * 3) IPU HSP clock is independent of AHB clock. Even it can go up to
264 * 177MHz for higher voltage, this function fixes the max to 133MHz.
265 * 4) This function should not have allowed diag_printf() calls since
266 * the serial driver has been stopped. But leave then here to allow
267 * easy debugging by NOT calling the cyg_hal_plf_serial_stop().
269 * @param ref pll input reference clock (24MHz)
270 * @param core_clk core clock in Hz
271 * @param emi_clk emi clock in Hz
272 # @return 0 if successful; non-zero otherwise
274 int configure_clock(u32 ref, u32 core_clk, u32 emi_clk)
277 struct pll_param pll_param;
278 int ret, clk_sel, div = 1, div_core = 1, div_per = 1, shift = 0;
279 u32 cbcdr = readl(CCM_BASE_ADDR + CLKCTL_CBCDR);
280 u32 cbcmr = readl(CCM_BASE_ADDR + CLKCTL_CBCMR);
281 u32 ccsr = readl(CCM_BASE_ADDR + CLKCTL_CCSR);
282 u32 icgc = readl(PLATFORM_BASE_ADDR + PLATFORM_ICGC);
284 dbg("%s: cbcdr[%08lx]=%08x\n", __FUNCTION__,
285 CCM_BASE_ADDR + CLKCTL_CBCDR, cbcdr);
286 dbg("%s: cbcmr[%08lx]=%08x\n", __FUNCTION__,
287 CCM_BASE_ADDR + CLKCTL_CBCMR, cbcdr);
288 dbg("%s: ccsr[%08lx]=%08x\n", __FUNCTION__,
289 CCM_BASE_ADDR + CLKCTL_CCSR, cbcdr);
290 dbg("%s: icgc[%08lx]=%08x\n", __FUNCTION__,
291 PLATFORM_BASE_ADDR + PLATFORM_ICGC, icgc);
294 // assume pll default to core clock first
296 if ((ret = calc_pll_params(ref, pll, &pll_param)) != 0) {
297 diag_printf("can't find pll parameters: %d\n", ret);
301 dbg("%s: ref=%d, pll=%d, pd=%d, mfi=%d,mfn=%d, mfd=%d\n", __FUNCTION__,
302 ref, pll, pll_param.pd, pll_param.mfi, pll_param.mfn, pll_param.mfd);
304 /* Applies for TO 2 only */
305 if (((cbcdr >> 30) & 0x1) == 0x1) {
306 /* Disable IPU and HSC dividers */
307 writel(0x60000, CCM_BASE_ADDR + CLKCTL_CCDR);
308 /* Switch DDR to different source */
309 writel(cbcdr & ~0x40000000, CCM_BASE_ADDR + CLKCTL_CBCDR);
310 while (readl(CCM_BASE_ADDR + CLKCTL_CDHIPR) != 0);
311 writel(0x0, CCM_BASE_ADDR + CLKCTL_CCDR);
314 /* Switch ARM to PLL2 clock */
315 writel(ccsr | 0x4, CCM_BASE_ADDR + CLKCTL_CCSR);
317 if ((core_clk > 665000000) && (core_clk <= 800000000)) {
319 } else if (core_clk > 800000000) {
325 if (core_clk > 800000000) {
327 increase_core_voltage(true);
330 increase_core_voltage(false);
332 cyg_hal_plf_serial_stop();
334 // adjust pll settings
335 writel(((pll_param.pd - 1) << 0) | (pll_param.mfi << 4),
336 PLL1_BASE_ADDR + PLL_DP_OP);
337 writel(pll_param.mfn, PLL1_BASE_ADDR + PLL_DP_MFN);
338 writel(pll_param.mfd - 1, PLL1_BASE_ADDR + PLL_DP_MFD);
339 writel(((pll_param.pd - 1) << 0) | (pll_param.mfi << 4),
340 PLL1_BASE_ADDR + PLL_DP_HFS_OP);
341 writel(pll_param.mfn, PLL1_BASE_ADDR + PLL_DP_HFS_MFN);
342 writel(pll_param.mfd - 1, PLL1_BASE_ADDR + PLL_DP_HFS_MFD);
345 icgc |= div_core << 4;
347 /* Set the platform clock dividers */
348 writel(icgc, PLATFORM_BASE_ADDR + PLATFORM_ICGC);
349 /* Switch ARM back to PLL1 */
350 writel((ccsr & ~0x4), CCM_BASE_ADDR + CLKCTL_CCSR);
351 /* Applies for TO 2 only */
352 if (((cbcdr >> 30) & 0x1) == 0x1) {
353 /* Disable IPU and HSC dividers */
354 writel(0x60000, CCM_BASE_ADDR + CLKCTL_CCDR);
355 /* Switch DDR back to PLL1 */
356 writel(cbcdr | 0x40000000, CCM_BASE_ADDR + CLKCTL_CBCDR);
357 while (readl(CCM_BASE_ADDR + CLKCTL_CDHIPR) != 0);
358 writel(0x0, CCM_BASE_ADDR + CLKCTL_CCDR);
360 /* Keep EMI clock to the max if not specified */
364 cyg_hal_plf_serial_init();
368 /* Applies for TO 2 only */
369 if (((cbcdr >> 30) & 0x1) == 0x1) {
370 clk_src = pll_clock(PLL1);
373 clk_src = get_periph_clk();
374 /* Find DDR clock input */
375 clk_sel = (cbcmr >> 10) & 0x3;
378 } else if (clk_sel == 1) {
380 } else if (clk_sel == 2) {
382 } else if (clk_sel == 3) {
386 if ((clk_src % emi_clk) == 0)
387 div = clk_src / emi_clk;
389 div = (clk_src / emi_clk) + 1;
393 cbcdr &= ~(0x7 << shift);
394 cbcdr |= (div - 1) << shift;
396 dbg("%s@%d: \n", __FUNCTION__, __LINE__);
398 /* Disable IPU and HSC dividers */
399 writel(0x60000, CCM_BASE_ADDR + CLKCTL_CCDR);
400 writel(cbcdr, CCM_BASE_ADDR + CLKCTL_CBCDR);
401 while (readl(CCM_BASE_ADDR + CLKCTL_CDHIPR) != 0);
402 writel(0x0, CCM_BASE_ADDR + CLKCTL_CCDR);
407 static void clock_setup(int argc,char *argv[])
409 u32 i, core_clk, ddr_clk, data[3];
417 for (i = 0; i < 2; i++) {
418 if (!parse_num(argv[1], &temp, &argv[1], ":")) {
419 diag_printf("Error: Invalid parameter\n");
425 core_clk = data[0] * SZ_DEC_1M;
426 ddr_clk = data[1] * SZ_DEC_1M;
429 if ((core_clk < PLL_FREQ_MIN(PLL_REF_CLK)) || (core_clk > PLL_FREQ_MAX(PLL_REF_CLK))) {
430 diag_printf("Targeted core clock should be within [%d - %d]\n",
431 PLL_FREQ_MIN(PLL_REF_CLK), PLL_FREQ_MAX(PLL_REF_CLK));
437 if (ddr_clk > MAX_DDR_CLK) {
438 diag_printf("DDR clock should be less than %d MHz, assuming max value\n",
439 MAX_DDR_CLK / SZ_DEC_1M);
440 ddr_clk = MAX_DDR_CLK;
445 ret = configure_clock(PLL_REF_CLK, core_clk, ddr_clk);
447 diag_printf("Failed to setup clock: %d\n", ret);
450 diag_printf("\n<<<New clock setting>>>\n");
452 // Now printing clocks
455 diag_printf("\nPLL1\t\tPLL2\t\tPLL3\t\tPLL4\n");
456 diag_printf("========================================================\n");
457 diag_printf("%-16d%-16d%-16d%-16d\n\n", pll_clock(PLL1), pll_clock(PLL2),
458 pll_clock(PLL3), pll_clock(PLL4));
459 diag_printf("AXI_A\t\tAXI_B\t\tEMI_SLOW_CLK\n");
460 diag_printf("========================================================\n");
461 diag_printf("%-16d%-16d%-16d\n\n",
462 get_main_clock(AXI_A_CLK),
463 get_main_clock(AXI_B_CLK),
464 get_main_clock(EMI_SLOW_CLK));
465 diag_printf("CPU\t\tAHB\t\tIPG\t\tDDR_CLK\n");
466 diag_printf("========================================================\n");
467 diag_printf("%-16d%-16d%-16d%-16d\n\n",
468 get_main_clock(CPU_CLK),
469 get_main_clock(AHB_CLK),
470 get_main_clock(IPG_CLK),
471 get_main_clock(DDR_CLK));
473 diag_printf("NFC\t\tUSB\t\tIPG_PER_CLK\n");
474 diag_printf("========================================\n");
475 diag_printf("%-16d%-16d%-16d\n\n",
476 get_main_clock(NFC_CLK),
477 get_main_clock(USB_CLK),
478 get_main_clock(IPG_PER_CLK));
480 diag_printf("UART1-3\t\tSSI1\t\tSSI2\t\tSPI\n");
481 diag_printf("===========================================");
482 diag_printf("=============\n");
484 diag_printf("%-16d%-16d%-16d%-16d\n\n",
485 get_peri_clock(UART1_BAUD),
486 get_peri_clock(SSI1_BAUD),
487 get_peri_clock(SSI2_BAUD),
488 get_peri_clock(SPI1_CLK));
491 diag_printf("IPG_PERCLK as baud clock for: UART1-5, I2C, OWIRE, SDHC");
492 if (((readl(EPIT1_BASE_ADDR) >> 24) & 0x3) == 0x2) {
493 diag_printf(", EPIT");
495 if (((readl(GPT1_BASE_ADDR) >> 6) & 0x7) == 0x2) {
496 diag_printf(", GPT");
504 * This function returns the PLL output value in Hz based on pll.
506 u32 pll_clock(enum plls pll)
509 u32 mfi, mfn, mfd, pdf, pll_out;
511 u32 dp_ctrl, dp_op, dp_mfd, dp_mfn;
515 dp_ctrl = pll_base[pll][PLL_DP_CTL >> 2];
516 clk_sel = MXC_GET_FIELD(dp_ctrl, 2, 8);
517 ref_clk = PLL_REF_CLK;
519 dbg("clk_sel=%d\n", clk_sel);
521 if ((pll_base[pll][PLL_DP_CTL >> 2] & 0x80) == 0) {
522 dp_op = pll_base[pll][PLL_DP_OP >> 2];
523 dp_mfd = pll_base[pll][PLL_DP_MFD >> 2];
524 dp_mfn = pll_base[pll][PLL_DP_MFN >> 2];
526 dp_op = pll_base[pll][PLL_DP_HFS_OP >> 2];
527 dp_mfd = pll_base[pll][PLL_DP_HFS_MFD >> 2];
528 dp_mfn = pll_base[pll][PLL_DP_HFS_MFN >> 2];
531 mfi = (dp_op >> 4) & 0xF;
532 mfi = (mfi <= 5) ? 5: mfi;
533 mfd = dp_mfd & 0x07FFFFFF;
534 mfn = dp_mfn & 0x07FFFFFF;
536 sign = (mfn < 0x4000000) ? 1 : -1;
537 mfn = (mfn < 0x4000000) ? mfn : (0x8000000 - mfn);
539 dbl = 2 * (((dp_ctrl >> 12) & 0x1) + 1);
541 dbg("%s: ref=%llu.%03lluMHz, dbl=%d, pd=%d, mfi=%d, mfn=%d, mfd=%d\n",
542 __FUNCTION__, ref_clk / 1000000, ref_clk / 1000 % 1000,
543 dbl, pdf + 1, mfi, sign * mfn, mfd + 1);
545 pll_out = (dbl * ref_clk * mfi + dbl * ref_clk * sign * mfn / (mfd + 1)) /
552 * This function returns the emi_core_clk_root clock.
554 u32 get_emi_core_clk(void)
556 u32 cbcdr = readl(CCM_BASE_ADDR + CLKCTL_CBCDR);
557 u32 clk_sel, max_pdf, peri_clk, ahb_clk;
560 max_pdf = (cbcdr >> 10) & 0x7;
561 peri_clk = get_periph_clk();
562 ahb_clk = peri_clk / (max_pdf + 1);
564 clk_sel = (cbcdr >> 26) & 1;
570 dbg("%s: CBCDR[%08lx]=%08x freq=%u.%03uMHz\n", __FUNCTION__,
571 CCM_BASE_ADDR + CLKCTL_CBCDR, cbcdr, ret_val / 1000000, ret_val / 1000 % 1000);
576 * This function returns the main clock value in Hz.
578 u32 get_main_clock(enum main_clocks clk)
580 u32 pdf, max_pdf, ipg_pdf, nfc_pdf, clk_sel;
582 u32 cacrr = readl(CCM_BASE_ADDR + CLKCTL_CACRR);
583 u32 cbcdr = readl(CCM_BASE_ADDR + CLKCTL_CBCDR);
584 u32 cbcmr = readl(CCM_BASE_ADDR + CLKCTL_CBCMR);
585 u32 cscmr1 = readl(CCM_BASE_ADDR + CLKCTL_CSCMR1);
586 u32 cscdr1 = readl(CCM_BASE_ADDR + CLKCTL_CSCDR1);
588 dbg("%s: \n", __FUNCTION__);
592 pll = pll_clock(PLL1);
593 ret_val = pll / (pdf + 1);
597 max_pdf = (cbcdr >> 10) & 0x7;
598 pll = get_periph_clk();
599 ret_val = pll / (max_pdf + 1);
603 pdf = (cbcdr >> 16) & 0x7;
604 pll = get_periph_clk();
605 ret_val = pll / (pdf + 1);
609 pdf = (cbcdr >> 19) & 0x7;
610 pll = get_periph_clk();
611 ret_val = pll / (pdf + 1);
615 pll = get_emi_core_clk();
616 pdf = (cbcdr >> 22) & 0x7;
617 ret_val = pll / (pdf + 1);
621 max_pdf = (cbcdr >> 10) & 0x7;
622 ipg_pdf = (cbcdr >> 8) & 0x3;
623 pll = get_periph_clk();
624 ret_val = pll / ((max_pdf + 1) * (ipg_pdf + 1));
630 clk_sel = (cbcmr >> 1) & 1;
631 pdf = (((cbcdr >> 6) & 3) + 1) * (((cbcdr >> 3) & 7) + 1) * ((cbcdr & 7) + 1);
633 ret_val = get_periph_clk() / pdf;
635 ret_val = get_lp_apm();
638 /* Same as IPG_CLK */
639 max_pdf = (cbcdr >> 10) & 0x7;
640 ipg_pdf = (cbcdr >> 8) & 0x3;
641 pll = get_periph_clk();
642 ret_val = pll / ((max_pdf + 1) * (ipg_pdf + 1));
647 clk_sel = (cbcmr >> 10) & 3;
648 pll = get_periph_clk();
651 pdf = (cbcdr >> 16) & 0x7;
652 } else if (clk_sel == 1) {
654 pdf = (cbcdr >> 19) & 0x7;
655 } else if (clk_sel == 2) {
656 /* EMI SLOW CLOCK ROOT */
657 pll = get_emi_core_clk();
658 pdf = (cbcdr >> 22) & 0x7;
659 } else if (clk_sel == 3) {
661 pdf = (cbcdr >> 10) & 0x7;
664 ret_val = pll / (pdf + 1);
668 pdf = (cbcdr >> 22) & 0x7;
669 nfc_pdf = (cbcdr >> 13) & 0x7;
670 pll = get_emi_core_clk();
671 ret_val = pll / ((pdf + 1) * (nfc_pdf + 1));
675 clk_sel = (cscmr1 >> 22) & 3;
677 pll = pll_clock(PLL1);
678 } else if (clk_sel == 1) {
679 pll = pll_clock(PLL2);
680 } else if (clk_sel == 2) {
681 pll = pll_clock(PLL3);
682 } else if (clk_sel == 3) {
685 pdf = (cscdr1 >> 8) & 0x7;
686 max_pdf = (cscdr1 >> 6) & 0x3;
687 ret_val = pll / ((pdf + 1) * (max_pdf + 1));
691 diag_printf("Unknown clock: %d\n", clk);
692 return ERR_WRONG_CLK;
699 * This function returns the peripheral clock value in Hz.
701 u32 get_peri_clock(enum peri_clocks clk)
703 u32 ret_val = 0, pdf, pre_pdf, clk_sel;
704 u32 cscmr1 = readl(CCM_BASE_ADDR + CLKCTL_CSCMR1);
705 u32 cscdr1 = readl(CCM_BASE_ADDR + CLKCTL_CSCDR1);
706 u32 cscdr2 = readl(CCM_BASE_ADDR + CLKCTL_CSCDR2);
707 u32 cs1cdr = readl(CCM_BASE_ADDR + CLKCTL_CS1CDR);
708 u32 cs2cdr = readl(CCM_BASE_ADDR + CLKCTL_CS2CDR);
710 dbg("%s: \n", __FUNCTION__);
715 pre_pdf = (cscdr1 >> 3) & 0x7;
717 clk_sel = (cscmr1 >> 24) & 3;
719 ret_val = pll_clock(PLL1) / ((pre_pdf + 1) * (pdf + 1));
720 } else if (clk_sel == 1) {
721 ret_val = pll_clock(PLL2) / ((pre_pdf + 1) * (pdf + 1));
722 } else if (clk_sel == 2) {
723 ret_val = pll_clock(PLL3) / ((pre_pdf + 1) * (pdf + 1));
725 ret_val = get_lp_apm() / ((pre_pdf + 1) * (pdf + 1));
729 pre_pdf = (cs1cdr >> 6) & 0x7;
731 clk_sel = (cscmr1 >> 14) & 3;
733 ret_val = pll_clock(PLL1) / ((pre_pdf + 1) * (pdf + 1));
734 } else if (clk_sel == 0x1) {
735 ret_val = pll_clock(PLL2) / ((pre_pdf + 1) * (pdf + 1));
736 } else if (clk_sel == 0x2) {
737 ret_val = pll_clock(PLL3) / ((pre_pdf + 1) * (pdf + 1));
739 ret_val = CKIH /((pre_pdf + 1) * (pdf + 1));
743 pre_pdf = (cs2cdr >> 6) & 0x7;
745 clk_sel = (cscmr1 >> 12) & 3;
747 ret_val = pll_clock(PLL1) / ((pre_pdf + 1) * (pdf + 1));
748 } else if (clk_sel == 0x1) {
749 ret_val = pll_clock(PLL2) / ((pre_pdf + 1) * (pdf + 1));
750 } else if (clk_sel == 0x2) {
751 ret_val = pll_clock(PLL3) / ((pre_pdf + 1) * (pdf + 1));
753 ret_val = CKIH /((pre_pdf + 1) * (pdf + 1));
758 pre_pdf = (cscdr2 >> 25) & 0x7;
759 pdf = (cscdr2 >> 19) & 0x3F;
760 clk_sel = (cscmr1 >> 4) & 3;
762 ret_val = pll_clock(PLL1) / ((pre_pdf + 1) * (pdf + 1));
763 } else if (clk_sel == 1) {
764 ret_val = pll_clock(PLL2) / ((pre_pdf + 1) * (pdf + 1));
765 } else if (clk_sel == 2) {
766 ret_val = pll_clock(PLL3) / ((pre_pdf + 1) * (pdf + 1));
768 ret_val = get_lp_apm() / ((pre_pdf + 1) * (pdf + 1));
772 diag_printf("%s(): This clock: %d not supported yet\n",
781 * This command is added for some simple testing only. It turns on/off
782 * L2 cache regardless of L1 cache state. The side effect of this is
783 * when doing any flash operations such as "fis init", the L2
784 * will be turned back on along with L1 caches even though it is off
785 * by using this command.
793 void do_L2_caches(int argc, char *argv[])
798 if (strcasecmp(argv[1], "on") == 0) {
799 HAL_DISABLE_INTERRUPTS(oldints);
801 HAL_RESTORE_INTERRUPTS(oldints);
802 } else if (strcasecmp(argv[1], "off") == 0) {
803 HAL_DISABLE_INTERRUPTS(oldints);
804 HAL_DCACHE_DISABLE_L1();
805 HAL_CACHE_FLUSH_ALL();
807 HAL_DCACHE_ENABLE_L1();
808 HAL_RESTORE_INTERRUPTS(oldints);
810 diag_printf("Invalid L2 cache mode: %s\n", argv[1]);
815 HAL_L2CACHE_IS_ENABLED(L2cache_on);
816 diag_printf("L2 cache: %s\n", L2cache_on ? "On" : "Off");
819 #endif //L2CC_ENABLED
821 #define IIM_ERR_SHIFT 8
822 #define POLL_FUSE_PRGD (IIM_STAT_PRGD | (IIM_ERR_PRGE << IIM_ERR_SHIFT))
823 #define POLL_FUSE_SNSD (IIM_STAT_SNSD | (IIM_ERR_SNSE << IIM_ERR_SHIFT))
825 static void fuse_op_start(void)
827 /* Do not generate interrupt */
828 writel(0, IIM_BASE_ADDR + IIM_STATM_OFF);
829 // clear the status bits and error bits
830 writel(0x3, IIM_BASE_ADDR + IIM_STAT_OFF);
831 writel(0xFE, IIM_BASE_ADDR + IIM_ERR_OFF);
835 * The action should be either:
840 static int poll_fuse_op_done(int action)
844 if (action != POLL_FUSE_PRGD && action != POLL_FUSE_SNSD) {
845 diag_printf("%s(%d) invalid operation\n", __FUNCTION__, action);
849 /* Poll busy bit till it is NOT set */
850 while ((readl(IIM_BASE_ADDR + IIM_STAT_OFF) & IIM_STAT_BUSY) != 0 ) {
853 /* Test for successful write */
854 status = readl(IIM_BASE_ADDR + IIM_STAT_OFF);
855 error = readl(IIM_BASE_ADDR + IIM_ERR_OFF);
857 if ((status & action) != 0 && (error & (action >> IIM_ERR_SHIFT)) == 0) {
859 diag_printf("Even though the operation seems successful...\n");
860 diag_printf("There are some error(s) at addr=0x%08lx: 0x%08x\n",
861 (IIM_BASE_ADDR + IIM_ERR_OFF), error);
865 diag_printf("%s(%d) failed\n", __FUNCTION__, action);
866 diag_printf("status address=0x%08lx, value=0x%08x\n",
867 (IIM_BASE_ADDR + IIM_STAT_OFF), status);
868 diag_printf("There are some error(s) at addr=0x%08lx: 0x%08x\n",
869 (IIM_BASE_ADDR + IIM_ERR_OFF), error);
873 unsigned int sense_fuse(int bank, int row, int bit)
875 int addr, addr_l, addr_h, reg_addr;
879 addr = ((bank << 11) | (row << 3) | (bit & 0x7));
880 /* Set IIM Program Upper Address */
881 addr_h = (addr >> 8) & 0x000000FF;
882 /* Set IIM Program Lower Address */
883 addr_l = (addr & 0x000000FF);
885 #ifdef IIM_FUSE_DEBUG
886 diag_printf("%s: addr_h=0x%02x, addr_l=0x%02x\n",
887 __FUNCTION__, addr_h, addr_l);
889 writel(addr_h, IIM_BASE_ADDR + IIM_UA_OFF);
890 writel(addr_l, IIM_BASE_ADDR + IIM_LA_OFF);
892 writel(0x8, IIM_BASE_ADDR + IIM_FCTL_OFF);
893 if (poll_fuse_op_done(POLL_FUSE_SNSD) != 0) {
894 diag_printf("%s(bank: %d, row: %d, bit: %d failed\n",
895 __FUNCTION__, bank, row, bit);
897 reg_addr = IIM_BASE_ADDR + IIM_SDAT_OFF;
898 return readl(reg_addr);
901 void do_fuse_read(int argc, char *argv[])
903 unsigned long bank, row;
904 unsigned long fuse_val;
907 diag_printf("Usage: fuse_read <bank> <row>\n");
909 } else if (argc == 3) {
910 if (!parse_num(argv[1], &bank, &argv[1], " ")) {
911 diag_printf("Error: Invalid parameter\n");
914 if (!parse_num(argv[2], &row, &argv[2], " ")) {
915 diag_printf("Error: Invalid parameter\n");
919 diag_printf("Read fuse at bank:%ld row:%ld\n", bank, row);
920 fuse_val = sense_fuse(bank, row, 0);
921 diag_printf("fuses at (bank:%ld, row:%ld) = 0x%02lx\n", bank, row, fuse_val);
923 diag_printf("Passing in wrong arguments: %d\n", argc);
924 diag_printf("Usage: fuse_read <bank> <row>\n");
928 /* Blow fuses based on the bank, row and bit positions (all 0-based)
930 static int fuse_blow(int bank, int row, int bit)
932 int addr, addr_l, addr_h, ret = -1;
936 /* Disable IIM Program Protect */
937 writel(0xAA, IIM_BASE_ADDR + IIM_PREG_P_OFF);
939 addr = ((bank << 11) | (row << 3) | (bit & 0x7));
940 /* Set IIM Program Upper Address */
941 addr_h = (addr >> 8) & 0x000000FF;
942 /* Set IIM Program Lower Address */
943 addr_l = (addr & 0x000000FF);
945 #ifdef IIM_FUSE_DEBUG
946 diag_printf("blowing fuse %d %d bit %d addr_h=0x%02x, addr_l=0x%02x\n",
947 bank, row, bit, addr_h, addr_l);
950 writel(addr_h, IIM_BASE_ADDR + IIM_UA_OFF);
951 writel(addr_l, IIM_BASE_ADDR + IIM_LA_OFF);
952 /* Start Programming */
953 writel(0x71, IIM_BASE_ADDR + IIM_FCTL_OFF);
954 if (poll_fuse_op_done(POLL_FUSE_PRGD) == 0) {
958 /* Enable IIM Program Protect */
959 writel(0x0, IIM_BASE_ADDR + IIM_PREG_P_OFF);
964 * This command is added for burning IIM fuses
966 RedBoot_cmd("fuse_read",
972 RedBoot_cmd("fuse_blow",
974 "<bank> <row> <value>",
978 void quick_itoa(u32 num, char *a)
981 for (i = 0; i <= 7; i++) {
982 j = (num >> (4 * i)) & 0xF;
983 k = (j < 10) ? '0' : ('a' - 0xa);
988 // slen - streng length, e.g.: 23 -> slen=2; abcd -> slen=4
989 // only convert hex value as string input. so "12" is 0x12.
990 u32 quick_atoi(char *a, u32 slen)
992 u32 i, num = 0, digit;
994 for (i = 0; i < slen; i++) {
995 if (a[i] >= '0' && a[i] <= '9') {
997 } else if (a[i] >= 'a' && a[i] <= 'f') {
998 digit = a[i] - 'a' + 10;
999 } else if (a[i] >= 'A' && a[i] <= 'F') {
1000 digit = a[i] - 'A' + 10;
1002 diag_printf("ERROR: %c\n", a[i]);
1005 num = (num * 16) + digit;
1010 void fuse_blow_row(int bank, int row, int value)
1012 unsigned int reg, i;
1016 // enable fuse blown
1017 reg = readl(CCM_BASE_ADDR + 0x64);
1019 writel(reg, CCM_BASE_ADDR + 0x64);
1021 for (i = 0; i < 8; i++) {
1022 if (((value >> i) & 0x1) == 0) {
1025 if (fuse_blow(bank, row, i) != 0) {
1026 diag_printf("fuse_blow(bank: %d, row: %d, bit: %d failed\n",
1031 writel(reg, CCM_BASE_ADDR + 0x64);
1036 void do_fuse_blow(int argc, char *argv[])
1038 unsigned long bank, row, value, i;
1039 unsigned int fuse_val;
1044 diag_printf("It is too dangeous for you to use this command.\n");
1049 if (strcasecmp(argv[1], "scc") == 0) {
1050 // fuse_blow scc C3D153EDFD2EA9982226EF5047D3B9A0B9C7138EA87C028401D28C2C2C0B9AA2
1051 diag_printf("Ready to burn SCC fuses\n");
1056 value = quick_atoi(val, 2);
1057 // diag_printf("fuse_blow_row(2, %d, value=0x%02x)\n", i, value);
1058 fuse_blow_row(2, i, value);
1060 if ((++s)[0] == '\0') {
1061 diag_printf("ERROR: Odd string input\n");
1064 if ((++s)[0] == '\0') {
1065 diag_printf("Successful\n");
1069 } else if (strcasecmp(argv[1], "srk") == 0) {
1070 // fuse_blow srk 418bccd09b53bee1ab59e2662b3c7877bc0094caee201052add49be8780dff95
1071 diag_printf("Ready to burn SRK key fuses\n");
1076 value = quick_atoi(val, 2);
1078 fuse_blow_row(1, 1, value); // 0x41 goes to SRK_HASH[255:248], bank 1, row 1
1080 fuse_blow_row(3, i, value); // 0x8b in SRK_HASH[247:240] bank 3, row 1
1081 // 0xcc in SRK_HASH[239:232] bank 3, row 2
1083 if ((++s)[0] == '\0') {
1084 diag_printf("ERROR: Odd string input\n");
1087 if ((++s)[0] == '\0') {
1088 diag_printf("Successful\n");
1093 diag_printf("This command is not supported\n");
1096 } else if (argc == 4) {
1097 if (!parse_num(argv[1], &bank, &argv[1], " ")) {
1098 diag_printf("Error: Invalid parameter\n");
1101 if (!parse_num(argv[2], &row, &argv[2], " ")) {
1102 diag_printf("Error: Invalid parameter\n");
1105 if (!parse_num(argv[3], &value, &argv[3], " ")) {
1106 diag_printf("Error: Invalid parameter\n");
1110 diag_printf("Blowing fuse at bank:%ld row:%ld value:%ld\n",
1112 fuse_blow_row(bank, row, value);
1113 fuse_val = sense_fuse(bank, row, 0);
1114 diag_printf("fuses at (bank:%ld, row:%ld) = 0x%02x\n", bank, row, fuse_val);
1117 diag_printf("Passing in wrong arguments: %d\n", argc);
1121 /* precondition: m>0 and n>0. Let g=gcd(m,n). */
1122 static int gcd(int m, int n)
1136 int read_mac_addr_from_fuse(unsigned char* data)
1138 data[0] = sense_fuse(1, 9, 0) ;
1139 data[1] = sense_fuse(1, 10, 0) ;
1140 data[2] = sense_fuse(1, 11, 0) ;
1141 data[3] = sense_fuse(1, 12, 0) ;
1142 data[4] = sense_fuse(1, 13, 0) ;
1143 data[5] = sense_fuse(1, 14, 0) ;
1145 if ((data[0] == 0) && (data[1] == 0) && (data[2] == 0) &&
1146 (data[3] == 0) && (data[4] == 0) && (data[5] == 0)) {
1154 void imx_power_mode(int mode)
1156 volatile unsigned int val;
1159 writel(0x0000030f, GPC_PGR);
1160 writel(0x1, SRPGCR_EMI);
1161 writel(0x1, SRPGCR_ARM);
1162 writel(0x1, PGC_PGCR_VPU);
1163 writel(0x1, PGC_PGCR_IPU);
1167 // stop mode - from validation code
1168 // Set DSM_INT_HOLDOFF bit in TZIC
1169 // If the TZIC didn't write the bit then there was interrupt pending
1170 // It will be serviced while we're in the loop
1171 // So we write to this bit again
1172 while (readl(INTC_BASE_ADDR + 0x14) == 0) {
1173 writel(1, INTC_BASE_ADDR + 0x14);
1183 diag_printf("Entering stop mode\n");
1184 val = readl(CCM_BASE_ADDR + 0x74);
1185 val = (val & 0xfffffffc) | 0x2; // set STOP mode
1186 writel(val, CCM_BASE_ADDR + 0x74);
1187 val = readl(PLATFORM_LPC_REG);
1188 writel(val | (1 << 16), PLATFORM_LPC_REG);// ENABLE DSM in ELBOW submodule of ARM platform
1189 writel(val | (1 << 17), PLATFORM_LPC_REG);// ENABLE DSM in ELBOW submodule of ARM platform
1196 asm("mcr p15, 0, r1, c7, c0, 4");
1199 void do_power_mode(int argc, char *argv[])
1204 diag_printf("Usage: power_mode <mode>\n");
1206 } else if (argc == 2) {
1207 if (!parse_num(argv[1], &mode, &argv[1], " ")) {
1208 diag_printf("Error: Invalid parameter\n");
1211 diag_printf("Entering power mode: %lu\n", mode);
1212 imx_power_mode(mode);
1215 diag_printf("Passing in wrong arguments: %d\n", argc);
1216 diag_printf("Usage: power_mode <mode>\n");
1221 * This command is added for burning IIM fuses
1223 RedBoot_cmd("power_mode",
1224 "Enter various power modes:",
1229 " <3> - STOP with Power-Gating\n"
1230 " -- need reset after issuing the command",
1235 /* Super Root key moduli */
1236 static const UINT8 hab_super_root_moduli[] = {
1238 0xb9, 0x84, 0xc8, 0x8a, 0xd3, 0x7e, 0xcc, 0xc0, 0xe7, 0x3e, 0x11, 0x53,
1239 0x6b, 0x5e, 0xea, 0xf4, 0xd9, 0xac, 0x5a, 0x63, 0x8a, 0x79, 0x96, 0x83,
1240 0xb1, 0x39, 0xb2, 0x6f, 0x9c, 0x54, 0x87, 0xf4, 0x3b, 0x9e, 0xd8, 0x0f,
1241 0x89, 0xf5, 0x01, 0x53, 0xb8, 0xe2, 0xcc, 0x75, 0x0d, 0xe1, 0x13, 0xfa,
1242 0xa7, 0xb9, 0x1e, 0xff, 0x6a, 0x05, 0xdb, 0x58, 0x10, 0xbf, 0x2b, 0xf4,
1243 0xe7, 0x0a, 0x63, 0x82, 0x2c, 0xa3, 0xb5, 0x0a, 0x72, 0x1c, 0xdc, 0x29,
1244 0xc1, 0x81, 0xb5, 0x9a, 0xf0, 0x25, 0x7d, 0xd6, 0xee, 0x01, 0x64, 0xc7,
1245 0x07, 0x2d, 0xcb, 0x31, 0x4c, 0x8d, 0x82, 0xf6, 0x44, 0x95, 0x4a, 0xbc,
1246 0xae, 0xe8, 0x2a, 0x89, 0xd4, 0xf2, 0x66, 0x72, 0x2b, 0x09, 0x4e, 0x56,
1247 0xe9, 0xbf, 0x5e, 0x38, 0x5c, 0xd5, 0x7e, 0x15, 0x55, 0x86, 0x0f, 0x19,
1248 0xf6, 0x00, 0xee, 0xa1, 0x92, 0x78, 0xef, 0x93, 0xcb, 0xfa, 0xb4, 0x98,
1249 0x19, 0xef, 0x10, 0x70, 0xde, 0x36, 0x1c, 0x12, 0x2e, 0xd2, 0x09, 0xc7,
1250 0x7b, 0xd1, 0xaa, 0xd3, 0x46, 0x65, 0xa1, 0x5b, 0xee, 0xa5, 0x96, 0x97,
1251 0x98, 0x3e, 0xfc, 0xf8, 0x74, 0x22, 0x51, 0xe7, 0xf1, 0x2f, 0x30, 0x79,
1252 0x13, 0xe5, 0x42, 0xc6, 0x7c, 0x18, 0x76, 0xd3, 0x7f, 0x5a, 0x13, 0xde,
1253 0x2f, 0x51, 0x07, 0xfa, 0x93, 0xfe, 0x10, 0x8a, 0x0c, 0x18, 0x60, 0x3c,
1254 0xff, 0x6a, 0x9b, 0xe7, 0x10, 0x2d, 0x71, 0xd2, 0x34, 0xc0, 0xdf, 0xbe,
1255 0x17, 0x4e, 0x75, 0x40, 0x83, 0xaa, 0x90, 0xd1, 0xed, 0xbd, 0xbf, 0xac,
1256 0x9a, 0x30, 0xbd, 0x69, 0x4d, 0xd8, 0x00, 0x63, 0x92, 0x69, 0x98, 0xf8,
1257 0x89, 0xdc, 0x7b, 0xe3, 0x66, 0x7e, 0xdd, 0xfa, 0x8c, 0x74, 0xe2, 0xb1,
1258 0xeb, 0x94, 0xf7, 0xab, 0x0e, 0x92, 0x06, 0xab, 0x60, 0xe5, 0x00, 0x43,
1259 0xb2, 0x5e, 0x6e, 0xeb
1262 /* Super Root key */
1263 const hab_rsa_public_key hab_super_root_key[] = {
1266 /* RSA public exponent, right-padded */
1267 0x01, 0x00, 0x01, 0x00,
1269 /* pointer to modulus data */
1270 hab_super_root_moduli,
1271 /* Exponent size in bytes */
1273 /* Modulus size in bytes */
1275 /* Key data valid */