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 #define IIM_FUSE_DEBUG
49 typedef unsigned long long u64;
50 typedef unsigned int u32;
51 typedef unsigned short u16;
52 typedef unsigned char u8;
54 u32 pll_clock(enum plls pll);
55 u32 get_main_clock(enum main_clocks clk);
56 u32 get_peri_clock(enum peri_clocks clk);
58 static void clock_setup(int argc, char *argv[]);
61 "Setup/Display clock\nSyntax:",
62 "[<ARM core clock in MHz> [:<ARM-AHB clock divider>]\n\
63 If a selection is zero or no divider is specified, the optimal divider values\n\
64 will be chosen. Examples:\n\
65 [clock] -> Show various clocks\n\
66 [clock 399] -> Core=399 AHB=133 IPG=66.5(AHB/2)\n\
67 [clock 532:4] -> Core=532 AHB=133(Core/4) IPG=66.5(AHB/2)\n\
68 [clock 399:4] -> Core=399 AHB=99.75(Core/4) IPG=49.875(AHB/2)\n\
69 [clock 199:3] -> Core=199.5 AHB=66.5(Core/3) IPG=33.25(AHB/2)\n\
70 [clock 133:2] -> Core=133 AHB=66.5(Core/2) IPG=33.25(AHB/2)\n\
71 Core range: 532-133, AHB range: 133-66.5, IPG is always AHB/2\n",
75 void clock_spi_enable(unsigned int spi_clk)
77 diag_printf("%s: stubbed\n", __func__);
80 static void clock_setup(int argc,char *argv[])
82 u32 i, data[2], core_clk, ahb_div, cctl, arm_src, arm_div;
88 for (i = 0; i < 2; i++) {
89 if (!parse_num(argv[1], &temp, &argv[1], ":")) {
90 diag_printf("Error: Invalid parameter\n");
97 ahb_div = data[1] - 1;
99 if (core_clk / (ahb_div + 1) > 133 ||
100 core_clk / (ahb_div + 1) < 66) {
101 diag_printf("Illegal AHB divider value specified\n");
128 diag_printf("Illegal core clock value specified\n");
132 cyg_hal_plf_serial_stop();
134 cctl = readl(CCM_BASE_ADDR + CLKCTL_CCTL);
136 cctl |= arm_div << 30;
137 cctl |= ahb_div << 28;
138 cctl |= arm_src << 14;
139 writel(cctl, CCM_BASE_ADDR + CLKCTL_CCTL);
142 cyg_hal_plf_serial_init();
144 diag_printf("\n<<<New clock settings>>>\n");
146 // Now printing clocks
148 diag_printf("\nMPLL\t\tUPLL\n");
149 diag_printf("=========================\n");
150 diag_printf("%-16d%-16d\n\n", pll_clock(MCU_PLL), pll_clock(USB_PLL));
151 diag_printf("CPU\t\tAHB\t\tIPG\n");
152 diag_printf("========================================\n");
153 diag_printf("%-16d%-16d%-16d\n\n",
154 get_main_clock(CPU_CLK),
155 get_main_clock(AHB_CLK),
156 get_main_clock(IPG_CLK));
158 diag_printf("UART\n");
159 diag_printf("========\n");
160 diag_printf("%-16d\n\n",
161 get_peri_clock(PER_UART_CLK));
163 diag_printf("SPI\n");
164 diag_printf("========\n");
165 diag_printf("%-16d\n\n",
166 get_peri_clock(SPI1_CLK));
170 * This function returns the PLL output value in Hz based on pll.
172 u32 pll_clock(enum plls pll)
174 int mfi, mfn, mfd, pdf;
176 u32 reg = readl(pll);
179 pdf = (reg >> 26) & 0xF;
180 mfd = (reg >> 16) & 0x3FF;
181 mfi = (reg >> 10) & 0xF;
189 ref_clk = PLL_REF_CLK;
191 pll_out = (2 * ref_clk * mfi + ((2 * ref_clk * mfn) / (mfd + 1))) /
197 * This function returns the main clock value in Hz.
199 u32 get_main_clock(enum main_clocks clk)
201 u32 cctl = readl(CCM_BASE_ADDR + CLKCTL_CCTL);
207 ret_val = pll_clock(MCU_PLL);
208 if (cctl & CRM_CCTL_ARM_SRC) {
209 ret_val = (ret_val * 3) / 4;
211 div = ((cctl >> CRM_CCTL_ARM_OFFSET) & 3) + 1;
216 div = ((cctl >> CRM_CCTL_AHB_OFFSET) & 3) + 1;
217 ret_val = get_main_clock(CPU_CLK) / div;
222 ret_val = get_main_clock(AHB_CLK) / 2;
226 diag_printf("Unknown clock: %d\n", clk);
233 * This function returns the peripheral clock value in Hz.
235 u32 get_peri_clock(enum peri_clocks clk)
242 pcdr = readl(CCM_BASE_ADDR + CLKCTL_PCDR3);
243 div = (pcdr >> 24) + 1;
244 ret_val = get_main_clock(AHB_CLK) / div;
249 ret_val = get_main_clock(IPG_CLK);
253 writel(readl(CCM_BASE_ADDR + CLKCTL_MCR) | (1 << 7),
254 CCM_BASE_ADDR + CLKCTL_MCR);
255 pcdr = readl(CCM_BASE_ADDR + CLKCTL_PCDR1);
256 pcdr &= ~(0xff << 24);
257 writel(pcdr, CCM_BASE_ADDR + CLKCTL_PCDR1);
258 div = (pcdr >> 24) + 1;
259 if (readl(CCM_BASE_ADDR + CLKCTL_MCR) & (1 << 7)) {
260 ret_val = pll_clock(USB_PLL) / div;
262 ret_val = get_main_clock(AHB_CLK) / div;
267 diag_printf("%s(): This clock: %d not supported yet\n",
274 #define IIM_ERR_SHIFT 8
275 #define POLL_FUSE_PRGD (IIM_STAT_PRGD | (IIM_ERR_PRGE << IIM_ERR_SHIFT))
276 #define POLL_FUSE_SNSD (IIM_STAT_SNSD | (IIM_ERR_SNSE << IIM_ERR_SHIFT))
278 static void fuse_op_start(void)
280 /* Do not generate interrupt */
281 writel(0, IIM_BASE_ADDR + IIM_STATM_OFF);
282 // clear the status bits and error bits
283 writel(0x3, IIM_BASE_ADDR + IIM_STAT_OFF);
284 writel(0xFE, IIM_BASE_ADDR + IIM_ERR_OFF);
288 * The action should be either:
293 static int poll_fuse_op_done(int action)
298 if (action != POLL_FUSE_PRGD && action != POLL_FUSE_SNSD) {
299 diag_printf("%s(%d) invalid operation\n", __FUNCTION__, action);
303 /* Poll busy bit till it is NOT set */
304 while ((readl(IIM_BASE_ADDR + IIM_STAT_OFF) & IIM_STAT_BUSY) != 0 ) {
307 /* Test for successful write */
308 status = readl(IIM_BASE_ADDR + IIM_STAT_OFF);
309 error = readl(IIM_BASE_ADDR + IIM_ERR_OFF);
311 if ((status & action) != 0 && (error & (action >> IIM_ERR_SHIFT)) == 0) {
313 diag_printf("Even though the operation seems successful...\n");
314 diag_printf("There are some error(s) at addr=0x%02lx: 0x%02x\n",
315 (IIM_BASE_ADDR + IIM_ERR_OFF), error);
319 diag_printf("%s(%d) failed\n", __FUNCTION__, action);
320 diag_printf("status address=0x%02lx, value=0x%02x\n",
321 (IIM_BASE_ADDR + IIM_STAT_OFF), status);
322 diag_printf("There are some error(s) at addr=0x%02lx: 0x%02x\n",
323 (IIM_BASE_ADDR + IIM_ERR_OFF), error);
327 static void sense_fuse(int bank, int row, int bit)
330 int addr, addr_l, addr_h, reg_addr;
334 addr = ((bank << 11) | (row << 3) | (bit & 0x7));
335 /* Set IIM Program Upper Address */
336 addr_h = (addr >> 8) & 0x000000FF;
337 /* Set IIM Program Lower Address */
338 addr_l = (addr & 0x000000FF);
340 #ifdef IIM_FUSE_DEBUG
341 diag_printf("%s: addr_h=0x%02x, addr_l=0x%02x\n",
342 __FUNCTION__, addr_h, addr_l);
344 writel(addr_h, IIM_BASE_ADDR + IIM_UA_OFF);
345 writel(addr_l, IIM_BASE_ADDR + IIM_LA_OFF);
347 writel(0x8, IIM_BASE_ADDR + IIM_FCTL_OFF);
348 if ((ret = poll_fuse_op_done(POLL_FUSE_SNSD)) != 0) {
349 diag_printf("%s(bank: %d, row: %d, bit: %d failed\n",
350 __FUNCTION__, bank, row, bit);
352 reg_addr = IIM_BASE_ADDR + IIM_SDAT_OFF;
354 diag_printf("fuses at (bank:%d, row:%d) = 0x%02x\n", bank, row, readl(reg_addr));
357 void do_fuse_read(int argc, char *argv[])
359 unsigned long bank, row;
362 diag_printf("Useage: fuse_read <bank> <row>\n");
364 } else if (argc == 3) {
365 if (!parse_num(argv[1], &bank, &argv[1], " ")) {
366 diag_printf("Error: Invalid parameter\n");
369 if (!parse_num(argv[2], &row, &argv[2], " ")) {
370 diag_printf("Error: Invalid parameter\n");
374 diag_printf("Read fuse at bank:%ld row:%ld\n", bank, row);
375 sense_fuse(bank, row, 0);
378 diag_printf("Passing in wrong arguments: %d\n", argc);
379 diag_printf("Useage: fuse_read <bank> <row>\n");
383 /* Blow fuses based on the bank, row and bit positions (all 0-based)
385 int fuse_blow(int bank, int row, int bit)
387 int addr, addr_l, addr_h, ret = -1;
391 /* Disable IIM Program Protect */
392 writel(0xAA, IIM_BASE_ADDR + IIM_PREG_P_OFF);
394 addr = ((bank << 11) | (row << 3) | (bit & 0x7));
395 /* Set IIM Program Upper Address */
396 addr_h = (addr >> 8) & 0x000000FF;
397 /* Set IIM Program Lower Address */
398 addr_l = (addr & 0x000000FF);
400 #ifdef IIM_FUSE_DEBUG
401 diag_printf("blowing fuse %d %d bit %d addr_h=0x%02x, addr_l=0x%02x\n",
402 bank, row, bit, addr_h, addr_l);
405 writel(addr_h, IIM_BASE_ADDR + IIM_UA_OFF);
406 writel(addr_l, IIM_BASE_ADDR + IIM_LA_OFF);
407 /* Start Programming */
408 writel(0x71, IIM_BASE_ADDR + IIM_FCTL_OFF);
409 if (poll_fuse_op_done(POLL_FUSE_PRGD) == 0) {
413 /* Enable IIM Program Protect */
414 writel(0x0, IIM_BASE_ADDR + IIM_PREG_P_OFF);
419 * This command is added for burning IIM fuses
421 RedBoot_cmd("fuse_read",
427 RedBoot_cmd("fuse_blow",
429 "<bank> <row> <value>",
433 #define INIT_STRING "12345678"
434 static char ready_to_blow[] = INIT_STRING;
436 void quick_itoa(u32 num, char *a)
439 for (i = 0; i <= 7; i++) {
440 j = (num >> (4 * i)) & 0xF;
441 k = (j < 10) ? '0' : ('a' - 0xa);
446 void do_fuse_blow(int argc, char *argv[])
448 unsigned long bank, row, value;
452 diag_printf("It is too dangeous for you to use this command.\n");
454 } else if (argc == 2) {
455 if (strcasecmp(argv[1], "nandboot") == 0) {
456 quick_itoa(readl(EPIT_BASE_ADDR + EPITCNR), ready_to_blow);
457 diag_printf("%s\n", ready_to_blow);
460 } else if (argc == 3) {
461 if (strcasecmp(argv[1], "nandboot") == 0 &&
462 strcasecmp(argv[2], ready_to_blow) == 0) {
463 #if defined(CYGPKG_HAL_ARM_MXC91131) || defined(CYGPKG_HAL_ARM_MX21) || \
464 defined(CYGPKG_HAL_ARM_MX27) || defined(CYGPKG_HAL_ARM_MX31) || \
465 defined(CYGPKG_HAL_ARM_MX35) || defined(CYGPKG_HAL_ARM_MX25)
466 diag_printf("No need to blow any fuses for NAND boot on this platform\n\n");
468 #error "Are you sure you want this?"
469 diag_printf("Ready to burn NAND boot fuses\n");
470 if (fuse_blow(0, 16, 1) != 0 || fuse_blow(0, 16, 7) != 0) {
471 diag_printf("NAND BOOT fuse blown failed miserably ...\n");
473 diag_printf("NAND BOOT fuse blown successfully ...\n");
476 diag_printf("Not ready: %s, %s\n", argv[1], argv[2]);
479 } else if (argc == 4) {
480 if (!parse_num(argv[1], &bank, &argv[1], " ")) {
481 diag_printf("Error: Invalid fuse bank\n");
484 if (!parse_num(argv[2], &row, &argv[2], " ")) {
485 diag_printf("Error: Invalid fuse row\n");
488 if (!parse_num(argv[3], &value, &argv[3], " ")) {
489 diag_printf("Error: Invalid value\n");
492 if (!verify_action("Confirm to blow fuse at bank:%ld row:%ld value:0x%02lx (%ld)",
494 diag_printf("fuse_blow canceled\n");
498 diag_printf("Blowing fuse at bank:%ld row:%ld value:%ld\n",
500 for (i = 0; i < 8; i++) {
501 if (((value >> i) & 0x1) == 0) {
504 if (fuse_blow(bank, row, i) != 0) {
505 diag_printf("fuse_blow(bank: %ld, row: %ld, bit: %d failed\n",
508 diag_printf("fuse_blow(bank: %ld, row: %ld, bit: %d successful\n",
512 sense_fuse(bank, row, 0);
514 diag_printf("Passing in wrong arguments: %d\n", argc);
516 /* Reset to default string */
517 strcpy(ready_to_blow, INIT_STRING);
520 /* precondition: m>0 and n>0. Let g=gcd(m,n). */
521 int gcd(int m, int n)
525 if (n > m) {t = m; m = n; n = t;} /* swap */