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_) ((4 * _ref_clk_ * PLL_MFI_MIN) / 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);
200 * This function returns the low power audio clock.
205 u32 ccsr = readl(CCM_BASE_ADDR + CLKCTL_CCSR);
207 if (((ccsr >> 9) & 1) == 0) {
208 ret_val = FREQ_24MHZ;
210 ret_val = FREQ_32768HZ;
212 dbg("%s: CCSR[%08lx]=%08x freq=%u.%03uMHz\n", __FUNCTION__,
213 CCM_BASE_ADDR + CLKCTL_CCSR, ccsr, ret_val / 1000000, ret_val / 1000 % 1000);
218 * This function returns the periph_clk.
220 u32 get_periph_clk(void)
222 u32 ret_val, clk_sel;
224 u32 cbcdr = readl(CCM_BASE_ADDR + CLKCTL_CBCDR);
225 u32 cbcmr = readl(CCM_BASE_ADDR + CLKCTL_CBCMR);
227 if (!(cbcdr & (1 << 25))) {
228 ret_val = pll_clock(PLL2);
229 dbg("%s: CBCDR[%08lx]=%08x CBCMR[%08lx]=%08x freq=%u.%03uMHz\n", __FUNCTION__,
230 CCM_BASE_ADDR + CLKCTL_CBCDR, cbcdr,
231 CCM_BASE_ADDR + CLKCTL_CBCMR, cbcmr,
232 ret_val / 1000000, ret_val / 1000 % 1000);
234 clk_sel = (cbcmr >> 12) & 3;
236 ret_val = pll_clock(PLL1);
237 } else if (clk_sel == 1) {
238 ret_val = pll_clock(PLL3);
239 } else if (clk_sel == 2) {
240 ret_val = get_lp_apm();
242 diag_printf("Invalid CBCMR[CLK_SEL]: %d\n", clk_sel);
243 return ERR_WRONG_CLK;
245 dbg("%s: CBCDR[%08lx]=%08x CBCMR[%08lx]=%08x clk_sel=%d freq=%u.%03uMHz\n", __FUNCTION__,
246 CCM_BASE_ADDR + CLKCTL_CBCDR, cbcdr,
247 CCM_BASE_ADDR + CLKCTL_CBCMR, cbcmr,
248 clk_sel, ret_val / 1000000, ret_val / 1000 % 1000);
254 * This function assumes the expected core clock has to be changed by
255 * modifying the PLL. This is NOT true always but for most of the times,
256 * it is. So it assumes the PLL output freq is the same as the expected
257 * core clock (presc=1) unless the core clock is less than PLL_FREQ_MIN.
258 * In the latter case, it will try to increase the presc value until
259 * (presc*core_clk) is greater than PLL_FREQ_MIN. It then makes call to
260 * calc_pll_params() and obtains the values of PD, MFI,MFN, MFD based
261 * on the targeted PLL and reference input clock to the PLL. Lastly,
262 * it sets the register based on these values along with the dividers.
263 * Note 1) There is no value checking for the passed-in divider values
264 * so the caller has to make sure those values are sensible.
265 * 2) Also adjust the NFC divider such that the NFC clock doesn't
266 * exceed NFC_CLK_MAX.
267 * 3) IPU HSP clock is independent of AHB clock. Even it can go up to
268 * 177MHz for higher voltage, this function fixes the max to 133MHz.
269 * 4) This function should not have allowed diag_printf() calls since
270 * the serial driver has been stopped. But leave then here to allow
271 * easy debugging by NOT calling the cyg_hal_plf_serial_stop().
273 * @param ref pll input reference clock (24MHz)
274 * @param core_clk core clock in Hz
275 * @param emi_clk emi clock in Hz
276 # @return 0 if successful; non-zero otherwise
278 int configure_clock(u32 ref, u32 core_clk, u32 emi_clk)
281 struct pll_param pll_param;
282 int ret, clk_sel, div = 1, div_core = 1, div_per = 1, shift = 0;
283 u32 cbcdr = readl(CCM_BASE_ADDR + CLKCTL_CBCDR);
284 u32 cbcmr = readl(CCM_BASE_ADDR + CLKCTL_CBCMR);
285 u32 ccsr = readl(CCM_BASE_ADDR + CLKCTL_CCSR);
286 u32 icgc = readl(PLATFORM_BASE_ADDR + PLATFORM_ICGC);
288 dbg("%s: cbcdr[%08lx]=%08x\n", __FUNCTION__,
289 CCM_BASE_ADDR + CLKCTL_CBCDR, cbcdr);
290 dbg("%s: cbcmr[%08lx]=%08x\n", __FUNCTION__,
291 CCM_BASE_ADDR + CLKCTL_CBCMR, cbcdr);
292 dbg("%s: ccsr[%08lx]=%08x\n", __FUNCTION__,
293 CCM_BASE_ADDR + CLKCTL_CCSR, cbcdr);
294 dbg("%s: icgc[%08lx]=%08x\n", __FUNCTION__,
295 PLATFORM_BASE_ADDR + PLATFORM_ICGC, icgc);
298 // assume pll default to core clock first
300 if ((ret = calc_pll_params(ref, pll, &pll_param)) != 0) {
301 diag_printf("can't find pll parameters: %d\n", ret);
305 dbg("%s: ref=%d, pll=%d, pd=%d, mfi=%d,mfn=%d, mfd=%d\n", __FUNCTION__,
306 ref, pll, pll_param.pd, pll_param.mfi, pll_param.mfn, pll_param.mfd);
308 /* Applies for TO 2 only */
309 if (((cbcdr >> 30) & 0x1) == 0x1) {
310 /* Disable IPU and HSC dividers */
311 writel(0x60000, CCM_BASE_ADDR + CLKCTL_CCDR);
312 /* Switch DDR to different source */
313 writel(cbcdr & ~0x40000000, CCM_BASE_ADDR + CLKCTL_CBCDR);
314 while (readl(CCM_BASE_ADDR + CLKCTL_CDHIPR) != 0);
315 writel(0x0, CCM_BASE_ADDR + CLKCTL_CCDR);
318 /* Switch ARM to PLL2 clock */
319 writel(ccsr | 0x4, CCM_BASE_ADDR + CLKCTL_CCSR);
321 if ((core_clk > 665000000) && (core_clk <= 800000000)) {
323 } else if (core_clk > 800000000) {
329 if (core_clk > 800000000) {
334 ret = adjust_core_voltage(core_clk / 1000000);
336 diag_printf("Failed to adjust core voltage for %u MHz\n",
340 cyg_hal_plf_serial_stop();
342 // adjust pll settings
343 writel(((pll_param.pd - 1) << 0) | (pll_param.mfi << 4),
344 PLL1_BASE_ADDR + PLL_DP_OP);
345 writel(pll_param.mfn, PLL1_BASE_ADDR + PLL_DP_MFN);
346 writel(pll_param.mfd - 1, PLL1_BASE_ADDR + PLL_DP_MFD);
347 writel(((pll_param.pd - 1) << 0) | (pll_param.mfi << 4),
348 PLL1_BASE_ADDR + PLL_DP_HFS_OP);
349 writel(pll_param.mfn, PLL1_BASE_ADDR + PLL_DP_HFS_MFN);
350 writel(pll_param.mfd - 1, PLL1_BASE_ADDR + PLL_DP_HFS_MFD);
353 icgc |= div_core << 4;
355 /* Set the platform clock dividers */
356 writel(icgc, PLATFORM_BASE_ADDR + PLATFORM_ICGC);
357 /* Switch ARM back to PLL1 */
358 writel((ccsr & ~0x4), CCM_BASE_ADDR + CLKCTL_CCSR);
359 /* Applies for TO 2 only */
360 if (((cbcdr >> 30) & 0x1) == 0x1) {
361 /* Disable IPU and HSC dividers */
362 writel(0x60000, CCM_BASE_ADDR + CLKCTL_CCDR);
363 /* Switch DDR back to PLL1 */
364 writel(cbcdr | 0x40000000, CCM_BASE_ADDR + CLKCTL_CBCDR);
365 while (readl(CCM_BASE_ADDR + CLKCTL_CDHIPR) != 0);
366 writel(0x0, CCM_BASE_ADDR + CLKCTL_CCDR);
368 /* Keep EMI clock to the max if not specified */
372 cyg_hal_plf_serial_init();
376 /* Applies for TO 2 only */
377 if (((cbcdr >> 30) & 0x1) == 0x1) {
378 clk_src = pll_clock(PLL1);
381 clk_src = get_periph_clk();
382 /* Find DDR clock input */
383 clk_sel = (cbcmr >> 10) & 0x3;
386 } else if (clk_sel == 1) {
388 } else if (clk_sel == 2) {
390 } else if (clk_sel == 3) {
394 if ((clk_src % emi_clk) == 0)
395 div = clk_src / emi_clk;
397 div = (clk_src / emi_clk) + 1;
401 cbcdr &= ~(0x7 << shift);
402 cbcdr |= (div - 1) << shift;
404 dbg("%s@%d: \n", __FUNCTION__, __LINE__);
406 /* Disable IPU and HSC dividers */
407 writel(0x60000, CCM_BASE_ADDR + CLKCTL_CCDR);
408 writel(cbcdr, CCM_BASE_ADDR + CLKCTL_CBCDR);
409 while (readl(CCM_BASE_ADDR + CLKCTL_CDHIPR) != 0);
410 writel(0x0, CCM_BASE_ADDR + CLKCTL_CCDR);
415 static void clock_setup(int argc,char *argv[])
417 u32 i, core_clk, ddr_clk, data[3];
425 for (i = 0; i < 2; i++) {
426 if (!parse_num(argv[1], &temp, &argv[1], ":")) {
427 diag_printf("Error: Invalid parameter\n");
433 core_clk = data[0] * SZ_DEC_1M;
434 ddr_clk = data[1] * SZ_DEC_1M;
437 if ((core_clk < PLL_FREQ_MIN(PLL_REF_CLK)) || (core_clk > PLL_FREQ_MAX(PLL_REF_CLK))) {
438 diag_printf("Targeted core clock should be within [%d - %d] MHz\n",
439 PLL_FREQ_MIN(PLL_REF_CLK) / SZ_DEC_1M,
440 PLL_FREQ_MAX(PLL_REF_CLK) / SZ_DEC_1M);
446 if (ddr_clk > MAX_DDR_CLK) {
447 diag_printf("DDR clock should be less than %d MHz, assuming max value\n",
448 MAX_DDR_CLK / SZ_DEC_1M);
449 ddr_clk = MAX_DDR_CLK;
454 ret = configure_clock(PLL_REF_CLK, core_clk, ddr_clk);
456 diag_printf("Failed to setup clock: %d\n", ret);
459 diag_printf("\n<<<New clock setting>>>\n");
461 // Now printing clocks
464 diag_printf("\nPLL1\t\tPLL2\t\tPLL3\t\tPLL4\n");
465 diag_printf("========================================================\n");
466 diag_printf("%-16d%-16d%-16d%-16d\n\n", pll_clock(PLL1), pll_clock(PLL2),
467 pll_clock(PLL3), pll_clock(PLL4));
468 diag_printf("AXI_A\t\tAXI_B\t\tEMI_SLOW_CLK\n");
469 diag_printf("========================================================\n");
470 diag_printf("%-16d%-16d%-16d\n\n",
471 get_main_clock(AXI_A_CLK),
472 get_main_clock(AXI_B_CLK),
473 get_main_clock(EMI_SLOW_CLK));
474 diag_printf("CPU\t\tAHB\t\tIPG\t\tDDR_CLK\n");
475 diag_printf("========================================================\n");
476 diag_printf("%-16d%-16d%-16d%-16d\n\n",
477 get_main_clock(CPU_CLK),
478 get_main_clock(AHB_CLK),
479 get_main_clock(IPG_CLK),
480 get_main_clock(DDR_CLK));
482 diag_printf("NFC\t\tUSB\t\tIPG_PER_CLK\n");
483 diag_printf("========================================\n");
484 diag_printf("%-16d%-16d%-16d\n\n",
485 get_main_clock(NFC_CLK),
486 get_main_clock(USB_CLK),
487 get_main_clock(IPG_PER_CLK));
489 diag_printf("UART1-3\t\tSSI1\t\tSSI2\t\tSPI\n");
490 diag_printf("===========================================");
491 diag_printf("=============\n");
493 diag_printf("%-16d%-16d%-16d%-16d\n\n",
494 get_peri_clock(UART1_BAUD),
495 get_peri_clock(SSI1_BAUD),
496 get_peri_clock(SSI2_BAUD),
497 get_peri_clock(SPI1_CLK));
500 diag_printf("IPG_PERCLK as baud clock for: UART1-5, I2C, OWIRE, SDHC");
501 if (((readl(EPIT1_BASE_ADDR) >> 24) & 0x3) == 0x2) {
502 diag_printf(", EPIT");
504 if (((readl(GPT1_BASE_ADDR) >> 6) & 0x7) == 0x2) {
505 diag_printf(", GPT");
513 * This function returns the PLL output value in Hz based on pll.
515 u32 pll_clock(enum plls pll)
518 u32 mfi, mfn, mfd, pdf, pll_out;
520 u32 dp_ctrl, dp_op, dp_mfd, dp_mfn;
524 dp_ctrl = pll_base[pll][PLL_DP_CTL >> 2];
525 clk_sel = MXC_GET_FIELD(dp_ctrl, 2, 8);
526 ref_clk = PLL_REF_CLK;
528 dbg("clk_sel=%d\n", clk_sel);
530 if ((pll_base[pll][PLL_DP_CTL >> 2] & 0x80) == 0) {
531 dp_op = pll_base[pll][PLL_DP_OP >> 2];
532 dp_mfd = pll_base[pll][PLL_DP_MFD >> 2];
533 dp_mfn = pll_base[pll][PLL_DP_MFN >> 2];
535 dp_op = pll_base[pll][PLL_DP_HFS_OP >> 2];
536 dp_mfd = pll_base[pll][PLL_DP_HFS_MFD >> 2];
537 dp_mfn = pll_base[pll][PLL_DP_HFS_MFN >> 2];
540 mfi = (dp_op >> 4) & 0xF;
541 mfi = (mfi <= 5) ? 5: mfi;
542 mfd = dp_mfd & 0x07FFFFFF;
543 mfn = dp_mfn & 0x07FFFFFF;
545 sign = (mfn < 0x4000000) ? 1 : -1;
546 mfn = (mfn < 0x4000000) ? mfn : (0x8000000 - mfn);
548 dbl = 2 * (((dp_ctrl >> 12) & 0x1) + 1);
550 dbg("%s: ref=%llu.%03lluMHz, dbl=%d, pd=%d, mfi=%d, mfn=%d, mfd=%d\n",
551 __FUNCTION__, ref_clk / 1000000, ref_clk / 1000 % 1000,
552 dbl, pdf + 1, mfi, sign * mfn, mfd + 1);
554 pll_out = (dbl * ref_clk * mfi + dbl * ref_clk * sign * mfn / (mfd + 1)) /
561 * This function returns the emi_core_clk_root clock.
563 u32 get_emi_core_clk(void)
565 u32 cbcdr = readl(CCM_BASE_ADDR + CLKCTL_CBCDR);
566 u32 clk_sel, max_pdf, peri_clk, ahb_clk;
569 max_pdf = (cbcdr >> 10) & 0x7;
570 peri_clk = get_periph_clk();
571 ahb_clk = peri_clk / (max_pdf + 1);
573 clk_sel = (cbcdr >> 26) & 1;
579 dbg("%s: CBCDR[%08lx]=%08x freq=%u.%03uMHz\n", __FUNCTION__,
580 CCM_BASE_ADDR + CLKCTL_CBCDR, cbcdr, ret_val / 1000000, ret_val / 1000 % 1000);
585 * This function returns the main clock value in Hz.
587 u32 get_main_clock(enum main_clocks clk)
589 u32 pdf, max_pdf, ipg_pdf, nfc_pdf, clk_sel;
591 u32 cacrr = readl(CCM_BASE_ADDR + CLKCTL_CACRR);
592 u32 cbcdr = readl(CCM_BASE_ADDR + CLKCTL_CBCDR);
593 u32 cbcmr = readl(CCM_BASE_ADDR + CLKCTL_CBCMR);
594 u32 cscmr1 = readl(CCM_BASE_ADDR + CLKCTL_CSCMR1);
595 u32 cscdr1 = readl(CCM_BASE_ADDR + CLKCTL_CSCDR1);
597 dbg("%s: \n", __FUNCTION__);
601 pll = pll_clock(PLL1);
602 ret_val = pll / (pdf + 1);
606 max_pdf = (cbcdr >> 10) & 0x7;
607 pll = get_periph_clk();
608 ret_val = pll / (max_pdf + 1);
612 pdf = (cbcdr >> 16) & 0x7;
613 pll = get_periph_clk();
614 ret_val = pll / (pdf + 1);
618 pdf = (cbcdr >> 19) & 0x7;
619 pll = get_periph_clk();
620 ret_val = pll / (pdf + 1);
624 pll = get_emi_core_clk();
625 pdf = (cbcdr >> 22) & 0x7;
626 ret_val = pll / (pdf + 1);
630 max_pdf = (cbcdr >> 10) & 0x7;
631 ipg_pdf = (cbcdr >> 8) & 0x3;
632 pll = get_periph_clk();
633 ret_val = pll / ((max_pdf + 1) * (ipg_pdf + 1));
639 clk_sel = (cbcmr >> 1) & 1;
640 pdf = (((cbcdr >> 6) & 3) + 1) * (((cbcdr >> 3) & 7) + 1) * ((cbcdr & 7) + 1);
642 ret_val = get_periph_clk() / pdf;
644 ret_val = get_lp_apm();
647 /* Same as IPG_CLK */
648 max_pdf = (cbcdr >> 10) & 0x7;
649 ipg_pdf = (cbcdr >> 8) & 0x3;
650 pll = get_periph_clk();
651 ret_val = pll / ((max_pdf + 1) * (ipg_pdf + 1));
656 clk_sel = (cbcmr >> 10) & 3;
657 pll = get_periph_clk();
660 pdf = (cbcdr >> 16) & 0x7;
661 } else if (clk_sel == 1) {
663 pdf = (cbcdr >> 19) & 0x7;
664 } else if (clk_sel == 2) {
665 /* EMI SLOW CLOCK ROOT */
666 pll = get_emi_core_clk();
667 pdf = (cbcdr >> 22) & 0x7;
668 } else if (clk_sel == 3) {
670 pdf = (cbcdr >> 10) & 0x7;
673 ret_val = pll / (pdf + 1);
677 pdf = (cbcdr >> 22) & 0x7;
678 nfc_pdf = (cbcdr >> 13) & 0x7;
679 pll = get_emi_core_clk();
680 ret_val = pll / ((pdf + 1) * (nfc_pdf + 1));
684 clk_sel = (cscmr1 >> 22) & 3;
686 pll = pll_clock(PLL1);
687 } else if (clk_sel == 1) {
688 pll = pll_clock(PLL2);
689 } else if (clk_sel == 2) {
690 pll = pll_clock(PLL3);
691 } else if (clk_sel == 3) {
694 pdf = (cscdr1 >> 8) & 0x7;
695 max_pdf = (cscdr1 >> 6) & 0x3;
696 ret_val = pll / ((pdf + 1) * (max_pdf + 1));
700 diag_printf("Unknown clock: %d\n", clk);
701 return ERR_WRONG_CLK;
708 * This function returns the peripheral clock value in Hz.
710 u32 get_peri_clock(enum peri_clocks clk)
712 u32 ret_val = 0, pdf, pre_pdf, clk_sel;
713 u32 cscmr1 = readl(CCM_BASE_ADDR + CLKCTL_CSCMR1);
714 u32 cscdr1 = readl(CCM_BASE_ADDR + CLKCTL_CSCDR1);
715 u32 cscdr2 = readl(CCM_BASE_ADDR + CLKCTL_CSCDR2);
716 u32 cs1cdr = readl(CCM_BASE_ADDR + CLKCTL_CS1CDR);
717 u32 cs2cdr = readl(CCM_BASE_ADDR + CLKCTL_CS2CDR);
719 dbg("%s: \n", __FUNCTION__);
724 pre_pdf = (cscdr1 >> 3) & 0x7;
726 clk_sel = (cscmr1 >> 24) & 3;
728 ret_val = pll_clock(PLL1) / ((pre_pdf + 1) * (pdf + 1));
729 } else if (clk_sel == 1) {
730 ret_val = pll_clock(PLL2) / ((pre_pdf + 1) * (pdf + 1));
731 } else if (clk_sel == 2) {
732 ret_val = pll_clock(PLL3) / ((pre_pdf + 1) * (pdf + 1));
734 ret_val = get_lp_apm() / ((pre_pdf + 1) * (pdf + 1));
738 pre_pdf = (cs1cdr >> 6) & 0x7;
740 clk_sel = (cscmr1 >> 14) & 3;
742 ret_val = pll_clock(PLL1) / ((pre_pdf + 1) * (pdf + 1));
743 } else if (clk_sel == 0x1) {
744 ret_val = pll_clock(PLL2) / ((pre_pdf + 1) * (pdf + 1));
745 } else if (clk_sel == 0x2) {
746 ret_val = pll_clock(PLL3) / ((pre_pdf + 1) * (pdf + 1));
748 ret_val = CKIH /((pre_pdf + 1) * (pdf + 1));
752 pre_pdf = (cs2cdr >> 6) & 0x7;
754 clk_sel = (cscmr1 >> 12) & 3;
756 ret_val = pll_clock(PLL1) / ((pre_pdf + 1) * (pdf + 1));
757 } else if (clk_sel == 0x1) {
758 ret_val = pll_clock(PLL2) / ((pre_pdf + 1) * (pdf + 1));
759 } else if (clk_sel == 0x2) {
760 ret_val = pll_clock(PLL3) / ((pre_pdf + 1) * (pdf + 1));
762 ret_val = CKIH /((pre_pdf + 1) * (pdf + 1));
767 pre_pdf = (cscdr2 >> 25) & 0x7;
768 pdf = (cscdr2 >> 19) & 0x3F;
769 clk_sel = (cscmr1 >> 4) & 3;
771 ret_val = pll_clock(PLL1) / ((pre_pdf + 1) * (pdf + 1));
772 } else if (clk_sel == 1) {
773 ret_val = pll_clock(PLL2) / ((pre_pdf + 1) * (pdf + 1));
774 } else if (clk_sel == 2) {
775 ret_val = pll_clock(PLL3) / ((pre_pdf + 1) * (pdf + 1));
777 ret_val = get_lp_apm() / ((pre_pdf + 1) * (pdf + 1));
781 diag_printf("%s(): This clock: %d not supported yet\n",
790 * This command is added for some simple testing only. It turns on/off
791 * L2 cache regardless of L1 cache state. The side effect of this is
792 * when doing any flash operations such as "fis init", the L2
793 * will be turned back on along with L1 caches even though it is off
794 * by using this command.
802 void do_L2_caches(int argc, char *argv[])
807 if (strcasecmp(argv[1], "on") == 0) {
808 HAL_DISABLE_INTERRUPTS(oldints);
810 HAL_RESTORE_INTERRUPTS(oldints);
811 } else if (strcasecmp(argv[1], "off") == 0) {
812 HAL_DISABLE_INTERRUPTS(oldints);
813 HAL_DCACHE_DISABLE_L1();
814 HAL_CACHE_FLUSH_ALL();
816 HAL_DCACHE_ENABLE_L1();
817 HAL_RESTORE_INTERRUPTS(oldints);
819 diag_printf("Invalid L2 cache mode: %s\n", argv[1]);
824 HAL_L2CACHE_IS_ENABLED(L2cache_on);
825 diag_printf("L2 cache: %s\n", L2cache_on ? "On" : "Off");
828 #endif //L2CC_ENABLED
830 #define IIM_ERR_SHIFT 8
831 #define POLL_FUSE_PRGD (IIM_STAT_PRGD | (IIM_ERR_PRGE << IIM_ERR_SHIFT))
832 #define POLL_FUSE_SNSD (IIM_STAT_SNSD | (IIM_ERR_SNSE << IIM_ERR_SHIFT))
834 static void fuse_op_start(void)
836 /* Do not generate interrupt */
837 writel(0, IIM_BASE_ADDR + IIM_STATM_OFF);
838 // clear the status bits and error bits
839 writel(0x3, IIM_BASE_ADDR + IIM_STAT_OFF);
840 writel(0xFE, IIM_BASE_ADDR + IIM_ERR_OFF);
844 * The action should be either:
849 static int poll_fuse_op_done(int action)
853 if (action != POLL_FUSE_PRGD && action != POLL_FUSE_SNSD) {
854 diag_printf("%s(%d) invalid operation\n", __FUNCTION__, action);
858 /* Poll busy bit till it is NOT set */
859 while ((readl(IIM_BASE_ADDR + IIM_STAT_OFF) & IIM_STAT_BUSY) != 0 ) {
862 /* Test for successful write */
863 status = readl(IIM_BASE_ADDR + IIM_STAT_OFF);
864 error = readl(IIM_BASE_ADDR + IIM_ERR_OFF);
866 if ((status & action) != 0 && (error & (action >> IIM_ERR_SHIFT)) == 0) {
868 diag_printf("Even though the operation seems successful...\n");
869 diag_printf("There are some error(s) at addr=0x%08lx: 0x%08x\n",
870 (IIM_BASE_ADDR + IIM_ERR_OFF), error);
874 diag_printf("%s(%d) failed\n", __FUNCTION__, action);
875 diag_printf("status address=0x%08lx, value=0x%08x\n",
876 (IIM_BASE_ADDR + IIM_STAT_OFF), status);
877 diag_printf("There are some error(s) at addr=0x%08lx: 0x%08x\n",
878 (IIM_BASE_ADDR + IIM_ERR_OFF), error);
882 unsigned int sense_fuse(int bank, int row, int bit)
884 int addr, addr_l, addr_h, reg_addr;
888 addr = ((bank << 11) | (row << 3) | (bit & 0x7));
889 /* Set IIM Program Upper Address */
890 addr_h = (addr >> 8) & 0x000000FF;
891 /* Set IIM Program Lower Address */
892 addr_l = (addr & 0x000000FF);
894 #ifdef IIM_FUSE_DEBUG
895 diag_printf("%s: addr_h=0x%02x, addr_l=0x%02x\n",
896 __FUNCTION__, addr_h, addr_l);
898 writel(addr_h, IIM_BASE_ADDR + IIM_UA_OFF);
899 writel(addr_l, IIM_BASE_ADDR + IIM_LA_OFF);
901 writel(0x8, IIM_BASE_ADDR + IIM_FCTL_OFF);
902 if (poll_fuse_op_done(POLL_FUSE_SNSD) != 0) {
903 diag_printf("%s(bank: %d, row: %d, bit: %d failed\n",
904 __FUNCTION__, bank, row, bit);
906 reg_addr = IIM_BASE_ADDR + IIM_SDAT_OFF;
907 return readl(reg_addr);
910 void do_fuse_read(int argc, char *argv[])
912 unsigned long bank, row;
913 unsigned long fuse_val;
916 diag_printf("Usage: fuse_read <bank> <row>\n");
918 } else if (argc == 3) {
919 if (!parse_num(argv[1], &bank, &argv[1], " ")) {
920 diag_printf("Error: Invalid parameter\n");
923 if (!parse_num(argv[2], &row, &argv[2], " ")) {
924 diag_printf("Error: Invalid parameter\n");
928 diag_printf("Read fuse at bank:%ld row:%ld\n", bank, row);
929 fuse_val = sense_fuse(bank, row, 0);
930 diag_printf("fuses at (bank:%ld, row:%ld) = 0x%02lx\n", bank, row, fuse_val);
932 diag_printf("Passing in wrong arguments: %d\n", argc);
933 diag_printf("Usage: fuse_read <bank> <row>\n");
937 /* Blow fuses based on the bank, row and bit positions (all 0-based)
939 static int fuse_blow(int bank, int row, int bit)
941 int addr, addr_l, addr_h, ret = -1;
945 /* Disable IIM Program Protect */
946 writel(0xAA, IIM_BASE_ADDR + IIM_PREG_P_OFF);
948 addr = ((bank << 11) | (row << 3) | (bit & 0x7));
949 /* Set IIM Program Upper Address */
950 addr_h = (addr >> 8) & 0x000000FF;
951 /* Set IIM Program Lower Address */
952 addr_l = (addr & 0x000000FF);
954 #ifdef IIM_FUSE_DEBUG
955 diag_printf("blowing fuse %d %d bit %d addr_h=0x%02x, addr_l=0x%02x\n",
956 bank, row, bit, addr_h, addr_l);
959 writel(addr_h, IIM_BASE_ADDR + IIM_UA_OFF);
960 writel(addr_l, IIM_BASE_ADDR + IIM_LA_OFF);
961 /* Start Programming */
962 writel(0x71, IIM_BASE_ADDR + IIM_FCTL_OFF);
963 if (poll_fuse_op_done(POLL_FUSE_PRGD) == 0) {
967 /* Enable IIM Program Protect */
968 writel(0x0, IIM_BASE_ADDR + IIM_PREG_P_OFF);
973 * This command is added for burning IIM fuses
975 RedBoot_cmd("fuse_read",
981 RedBoot_cmd("fuse_blow",
983 "<bank> <row> <value>",
987 void quick_itoa(u32 num, char *a)
990 for (i = 0; i <= 7; i++) {
991 j = (num >> (4 * i)) & 0xF;
992 k = (j < 10) ? '0' : ('a' - 0xa);
997 // slen - streng length, e.g.: 23 -> slen=2; abcd -> slen=4
998 // only convert hex value as string input. so "12" is 0x12.
999 u32 quick_atoi(char *a, u32 slen)
1001 u32 i, num = 0, digit;
1003 for (i = 0; i < slen; i++) {
1004 if (a[i] >= '0' && a[i] <= '9') {
1006 } else if (a[i] >= 'a' && a[i] <= 'f') {
1007 digit = a[i] - 'a' + 10;
1008 } else if (a[i] >= 'A' && a[i] <= 'F') {
1009 digit = a[i] - 'A' + 10;
1011 diag_printf("ERROR: %c\n", a[i]);
1014 num = (num * 16) + digit;
1019 void fuse_blow_row(int bank, int row, int value)
1021 unsigned int reg, i;
1025 // enable fuse blown
1026 reg = readl(CCM_BASE_ADDR + 0x64);
1028 writel(reg, CCM_BASE_ADDR + 0x64);
1030 for (i = 0; i < 8; i++) {
1031 if (((value >> i) & 0x1) == 0) {
1034 if (fuse_blow(bank, row, i) != 0) {
1035 diag_printf("fuse_blow(bank: %d, row: %d, bit: %d failed\n",
1040 writel(reg, CCM_BASE_ADDR + 0x64);
1045 void do_fuse_blow(int argc, char *argv[])
1047 unsigned long bank, row, value, i;
1048 unsigned int fuse_val;
1053 diag_printf("It is too dangeous for you to use this command.\n");
1058 if (strcasecmp(argv[1], "scc") == 0) {
1059 // fuse_blow scc C3D153EDFD2EA9982226EF5047D3B9A0B9C7138EA87C028401D28C2C2C0B9AA2
1060 diag_printf("Ready to burn SCC fuses\n");
1065 value = quick_atoi(val, 2);
1066 // diag_printf("fuse_blow_row(2, %d, value=0x%02x)\n", i, value);
1067 fuse_blow_row(2, i, value);
1069 if ((++s)[0] == '\0') {
1070 diag_printf("ERROR: Odd string input\n");
1073 if ((++s)[0] == '\0') {
1074 diag_printf("Successful\n");
1078 } else if (strcasecmp(argv[1], "srk") == 0) {
1079 // fuse_blow srk 418bccd09b53bee1ab59e2662b3c7877bc0094caee201052add49be8780dff95
1080 diag_printf("Ready to burn SRK key fuses\n");
1085 value = quick_atoi(val, 2);
1087 fuse_blow_row(1, 1, value); // 0x41 goes to SRK_HASH[255:248], bank 1, row 1
1089 fuse_blow_row(3, i, value); // 0x8b in SRK_HASH[247:240] bank 3, row 1
1090 // 0xcc in SRK_HASH[239:232] bank 3, row 2
1092 if ((++s)[0] == '\0') {
1093 diag_printf("ERROR: Odd string input\n");
1096 if ((++s)[0] == '\0') {
1097 diag_printf("Successful\n");
1102 diag_printf("This command is not supported\n");
1105 } else if (argc == 4) {
1106 if (!parse_num(argv[1], &bank, &argv[1], " ")) {
1107 diag_printf("Error: Invalid parameter\n");
1110 if (!parse_num(argv[2], &row, &argv[2], " ")) {
1111 diag_printf("Error: Invalid parameter\n");
1114 if (!parse_num(argv[3], &value, &argv[3], " ")) {
1115 diag_printf("Error: Invalid parameter\n");
1119 diag_printf("Blowing fuse at bank:%ld row:%ld value:%ld\n",
1121 fuse_blow_row(bank, row, value);
1122 fuse_val = sense_fuse(bank, row, 0);
1123 diag_printf("fuses at (bank:%ld, row:%ld) = 0x%02x\n", bank, row, fuse_val);
1126 diag_printf("Passing in wrong arguments: %d\n", argc);
1130 /* precondition: m>0 and n>0. Let g=gcd(m,n). */
1131 static int gcd(int m, int n)
1145 int read_mac_addr_from_fuse(unsigned char* data)
1147 data[0] = sense_fuse(1, 9, 0) ;
1148 data[1] = sense_fuse(1, 10, 0) ;
1149 data[2] = sense_fuse(1, 11, 0) ;
1150 data[3] = sense_fuse(1, 12, 0) ;
1151 data[4] = sense_fuse(1, 13, 0) ;
1152 data[5] = sense_fuse(1, 14, 0) ;
1154 if ((data[0] == 0) && (data[1] == 0) && (data[2] == 0) &&
1155 (data[3] == 0) && (data[4] == 0) && (data[5] == 0)) {
1163 void imx_power_mode(int mode)
1165 volatile unsigned int val;
1168 writel(0x0000030f, GPC_PGR);
1169 writel(0x1, SRPGCR_EMI);
1170 writel(0x1, SRPGCR_ARM);
1171 writel(0x1, PGC_PGCR_VPU);
1172 writel(0x1, PGC_PGCR_IPU);
1176 // stop mode - from validation code
1177 // Set DSM_INT_HOLDOFF bit in TZIC
1178 // If the TZIC didn't write the bit then there was interrupt pending
1179 // It will be serviced while we're in the loop
1180 // So we write to this bit again
1181 while (readl(INTC_BASE_ADDR + 0x14) == 0) {
1182 writel(1, INTC_BASE_ADDR + 0x14);
1192 diag_printf("Entering stop mode\n");
1193 val = readl(CCM_BASE_ADDR + 0x74);
1194 val = (val & 0xfffffffc) | 0x2; // set STOP mode
1195 writel(val, CCM_BASE_ADDR + 0x74);
1196 val = readl(PLATFORM_LPC_REG);
1197 writel(val | (1 << 16), PLATFORM_LPC_REG);// ENABLE DSM in ELBOW submodule of ARM platform
1198 writel(val | (1 << 17), PLATFORM_LPC_REG);// ENABLE DSM in ELBOW submodule of ARM platform
1205 asm("mcr p15, 0, r1, c7, c0, 4");
1208 void do_power_mode(int argc, char *argv[])
1213 diag_printf("Usage: power_mode <mode>\n");
1215 } else if (argc == 2) {
1216 if (!parse_num(argv[1], &mode, &argv[1], " ")) {
1217 diag_printf("Error: Invalid parameter\n");
1220 diag_printf("Entering power mode: %lu\n", mode);
1221 imx_power_mode(mode);
1224 diag_printf("Passing in wrong arguments: %d\n", argc);
1225 diag_printf("Usage: power_mode <mode>\n");
1230 * This command is added for burning IIM fuses
1232 RedBoot_cmd("power_mode",
1233 "Enter various power modes:",
1238 " <3> - STOP with Power-Gating\n"
1239 " -- need reset after issuing the command",
1244 /* Super Root key moduli */
1245 static const UINT8 hab_super_root_moduli[] = {
1247 0xb9, 0x84, 0xc8, 0x8a, 0xd3, 0x7e, 0xcc, 0xc0, 0xe7, 0x3e, 0x11, 0x53,
1248 0x6b, 0x5e, 0xea, 0xf4, 0xd9, 0xac, 0x5a, 0x63, 0x8a, 0x79, 0x96, 0x83,
1249 0xb1, 0x39, 0xb2, 0x6f, 0x9c, 0x54, 0x87, 0xf4, 0x3b, 0x9e, 0xd8, 0x0f,
1250 0x89, 0xf5, 0x01, 0x53, 0xb8, 0xe2, 0xcc, 0x75, 0x0d, 0xe1, 0x13, 0xfa,
1251 0xa7, 0xb9, 0x1e, 0xff, 0x6a, 0x05, 0xdb, 0x58, 0x10, 0xbf, 0x2b, 0xf4,
1252 0xe7, 0x0a, 0x63, 0x82, 0x2c, 0xa3, 0xb5, 0x0a, 0x72, 0x1c, 0xdc, 0x29,
1253 0xc1, 0x81, 0xb5, 0x9a, 0xf0, 0x25, 0x7d, 0xd6, 0xee, 0x01, 0x64, 0xc7,
1254 0x07, 0x2d, 0xcb, 0x31, 0x4c, 0x8d, 0x82, 0xf6, 0x44, 0x95, 0x4a, 0xbc,
1255 0xae, 0xe8, 0x2a, 0x89, 0xd4, 0xf2, 0x66, 0x72, 0x2b, 0x09, 0x4e, 0x56,
1256 0xe9, 0xbf, 0x5e, 0x38, 0x5c, 0xd5, 0x7e, 0x15, 0x55, 0x86, 0x0f, 0x19,
1257 0xf6, 0x00, 0xee, 0xa1, 0x92, 0x78, 0xef, 0x93, 0xcb, 0xfa, 0xb4, 0x98,
1258 0x19, 0xef, 0x10, 0x70, 0xde, 0x36, 0x1c, 0x12, 0x2e, 0xd2, 0x09, 0xc7,
1259 0x7b, 0xd1, 0xaa, 0xd3, 0x46, 0x65, 0xa1, 0x5b, 0xee, 0xa5, 0x96, 0x97,
1260 0x98, 0x3e, 0xfc, 0xf8, 0x74, 0x22, 0x51, 0xe7, 0xf1, 0x2f, 0x30, 0x79,
1261 0x13, 0xe5, 0x42, 0xc6, 0x7c, 0x18, 0x76, 0xd3, 0x7f, 0x5a, 0x13, 0xde,
1262 0x2f, 0x51, 0x07, 0xfa, 0x93, 0xfe, 0x10, 0x8a, 0x0c, 0x18, 0x60, 0x3c,
1263 0xff, 0x6a, 0x9b, 0xe7, 0x10, 0x2d, 0x71, 0xd2, 0x34, 0xc0, 0xdf, 0xbe,
1264 0x17, 0x4e, 0x75, 0x40, 0x83, 0xaa, 0x90, 0xd1, 0xed, 0xbd, 0xbf, 0xac,
1265 0x9a, 0x30, 0xbd, 0x69, 0x4d, 0xd8, 0x00, 0x63, 0x92, 0x69, 0x98, 0xf8,
1266 0x89, 0xdc, 0x7b, 0xe3, 0x66, 0x7e, 0xdd, 0xfa, 0x8c, 0x74, 0xe2, 0xb1,
1267 0xeb, 0x94, 0xf7, 0xab, 0x0e, 0x92, 0x06, 0xab, 0x60, 0xe5, 0x00, 0x43,
1268 0xb2, 0x5e, 0x6e, 0xeb
1271 /* Super Root key */
1272 const hab_rsa_public_key hab_super_root_key[] = {
1275 /* RSA public exponent, right-padded */
1276 0x01, 0x00, 0x01, 0x00,
1278 /* pointer to modulus data */
1279 hab_super_root_moduli,
1280 /* Exponent size in bytes */
1282 /* Modulus size in bytes */
1284 /* Key data valid */