]> git.kernelconcepts.de Git - karo-tx-redboot.git/blob - packages/hal/arm/mx25/var/v2_0/src/cmds.c
Initial revision
[karo-tx-redboot.git] / packages / hal / arm / mx25 / var / v2_0 / src / cmds.c
1 //==========================================================================
2 //
3 //      cmds.c
4 //
5 //      SoC [platform] specific RedBoot commands
6 //
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.
12 //
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.
16 //
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
20 // for more details.
21 //
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.
25 //
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.
32 //
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.
35 //
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 //==========================================================================
41 #include <redboot.h>
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
47 #define IIM_FUSE_DEBUG
48
49 typedef unsigned long long  u64;
50 typedef unsigned int        u32;
51 typedef unsigned short      u16;
52 typedef unsigned char       u8;
53
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);
57
58 static void clock_setup(int argc, char *argv[]);
59
60 RedBoot_cmd("clock",
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",
72             clock_setup
73            );
74
75 void clock_spi_enable(unsigned int spi_clk)
76 {
77     diag_printf("%s: stubbed\n", __func__);
78 }
79
80 static void clock_setup(int argc,char *argv[])
81 {
82     u32 i, data[2], temp, core_clk, ahb_div, cctl, arm_src, arm_div;
83
84     if (argc == 1)
85         goto print_clock;
86
87     for (i = 0;  i < 2;  i++) {
88         if (!parse_num(*(&argv[1]), (unsigned long *)&temp, &argv[1], ":")) {
89             diag_printf("Error: Invalid parameter\n");
90             return;
91         }
92         data[i] = temp;
93     }
94
95     core_clk = data[0];
96     ahb_div = data[1] - 1;
97
98     if (core_clk / (ahb_div + 1) > 133 ||
99         core_clk / (ahb_div + 1) < 66) {
100         diag_printf("Illegal AHB divider value specified\n");
101         return;
102     }
103
104     switch (core_clk) {
105     case 532:
106         arm_src = 0;
107         arm_div = 1 - 1;
108         break;
109     case 399:
110         arm_src = 1;
111         arm_div = 1 - 1;
112         break;
113     case 199:
114     case 200:
115         arm_src = 1;
116         arm_div = 2 - 1;
117         break;
118     case 133:
119         arm_src = 1;
120         arm_div = 3 - 1;
121         break;
122     default:
123         diag_printf("Illegal core clock value specified\n");
124         return;
125     }
126
127     cctl = readl(CCM_BASE_ADDR + CLKCTL_CCTL);
128     cctl &= ~0xF0004000;
129     cctl |= arm_div << 30;
130     cctl |= ahb_div << 28;
131     cctl |= arm_src << 14;
132     writel(cctl, CCM_BASE_ADDR + CLKCTL_CCTL);
133
134     diag_printf("\n<<<New clock settings>>>\n");
135
136     // Now printing clocks
137 print_clock:
138     diag_printf("\nMPLL\t\tUPLL\n");
139     diag_printf("=========================\n");
140     diag_printf("%-16d%-16d\n\n", pll_clock(MCU_PLL), pll_clock(USB_PLL));
141     diag_printf("CPU\t\tAHB\t\tIPG\n");
142     diag_printf("========================================\n");
143     diag_printf("%-16d%-16d%-16d\n\n",
144                 get_main_clock(CPU_CLK),
145                 get_main_clock(AHB_CLK),
146                 get_main_clock(IPG_CLK));
147
148     diag_printf("UART\n");
149     diag_printf("========\n");
150     diag_printf("%-16d\n\n",
151                 get_peri_clock(PER_UART_CLK));
152
153     diag_printf("SPI\n");
154     diag_printf("========\n");
155     diag_printf("%-16d\n\n",
156                 get_peri_clock(SPI1_CLK));
157 }
158
159 /*!
160  * This function returns the PLL output value in Hz based on pll.
161  */
162 u32 pll_clock(enum plls pll)
163 {
164     u64 mfi, mfn, mfd, pdf, ref_clk, pll_out;
165     u64 reg = readl(pll);
166
167     pdf = (reg >> 26) & 0xF;
168     mfd = (reg >> 16) & 0x3FF;
169     mfi = (reg >> 10) & 0xF;
170     mfi = (mfi <= 5) ? 5: mfi;
171     mfn = reg & 0x3FF;
172
173     ref_clk = PLL_REF_CLK;
174
175     pll_out = (2 * ref_clk * mfi + ((2 * ref_clk * mfn) / (mfd + 1))) /
176               (pdf + 1);
177
178     return (u32)pll_out;
179 }
180
181 /*!
182  * This function returns the main clock value in Hz.
183  */
184 u32 get_main_clock(enum main_clocks clk)
185 {
186     u32 cctl = readl(CCM_BASE_ADDR + CLKCTL_CCTL);
187     u32 ahb_div;
188     u32 ret_val = 0;
189
190     switch (clk) {
191     case CPU_CLK:
192         ret_val = pll_clock(MCU_PLL);
193         if (cctl & CRM_CCTL_ARM_SRC) {
194                 ret_val *= 3;
195                 ret_val /= 4;
196         }
197         break;
198     case AHB_CLK:
199         ahb_div = ((cctl >> CRM_CCTL_AHB_OFFSET) & 3) + 1;
200         ret_val = get_main_clock(CPU_CLK) / ahb_div;
201         break;
202     case IPG_CLK:
203     case IPG_PER_CLK:
204         ret_val = get_main_clock(AHB_CLK) / 2;
205         break;
206     default:
207         diag_printf("Unknown clock: %d\n", clk);
208         break;
209     }
210
211     return ret_val;
212 }
213
214 /*!
215  * This function returns the peripheral clock value in Hz.
216  */
217 u32 get_peri_clock(enum peri_clocks clk)
218 {
219     u32 ret_val = 0;
220     u32 pcdr, div;
221
222     switch (clk) {
223     case PER_UART_CLK:
224         pcdr = readl(CCM_BASE_ADDR + CLKCTL_PCDR3);
225         div = (pcdr >> 24) + 1;
226         ret_val = get_main_clock(AHB_CLK) / div;
227         break;
228     case SPI1_CLK:
229     case SPI2_CLK:
230         ret_val = get_main_clock(IPG_CLK);
231         break;
232     default:
233         diag_printf("%s(): This clock: %d not supported yet \n",
234                     __FUNCTION__, clk);
235         break;
236     }
237     return ret_val;
238 }
239
240
241 #define IIM_ERR_SHIFT       8
242 #define POLL_FUSE_PRGD      (IIM_STAT_PRGD | (IIM_ERR_PRGE << IIM_ERR_SHIFT))
243 #define POLL_FUSE_SNSD      (IIM_STAT_SNSD | (IIM_ERR_SNSE << IIM_ERR_SHIFT))
244
245 static void fuse_op_start(void)
246 {
247     /* Do not generate interrupt */
248     writel(0, IIM_BASE_ADDR + IIM_STATM_OFF);
249     // clear the status bits and error bits
250     writel(0x3, IIM_BASE_ADDR + IIM_STAT_OFF);
251     writel(0xFE, IIM_BASE_ADDR + IIM_ERR_OFF);
252 }
253
254 /*
255  * The action should be either:
256  *          POLL_FUSE_PRGD
257  * or:
258  *          POLL_FUSE_SNSD
259  */
260 static int poll_fuse_op_done(int action)
261 {
262
263     u32 status, error;
264
265     if (action != POLL_FUSE_PRGD && action != POLL_FUSE_SNSD) {
266         diag_printf("%s(%d) invalid operation\n", __FUNCTION__, action);
267         return -1;
268     }
269
270     /* Poll busy bit till it is NOT set */
271     while ((readl(IIM_BASE_ADDR + IIM_STAT_OFF) & IIM_STAT_BUSY) != 0 ) {
272     }
273
274     /* Test for successful write */
275     status = readl(IIM_BASE_ADDR + IIM_STAT_OFF);
276     error = readl(IIM_BASE_ADDR + IIM_ERR_OFF);
277
278     if ((status & action) != 0 && (error & (action >> IIM_ERR_SHIFT)) == 0) {
279         if (error) {
280             diag_printf("Even though the operation seems successful...\n");
281             diag_printf("There are some error(s) at addr=0x%x: 0x%x\n",
282                         (IIM_BASE_ADDR + IIM_ERR_OFF), error);
283         }
284         return 0;
285     }
286     diag_printf("%s(%d) failed\n", __FUNCTION__, action);
287     diag_printf("status address=0x%x, value=0x%x\n",
288                 (IIM_BASE_ADDR + IIM_STAT_OFF), status);
289     diag_printf("There are some error(s) at addr=0x%x: 0x%x\n",
290                 (IIM_BASE_ADDR + IIM_ERR_OFF), error);
291     return -1;
292 }
293
294 static void sense_fuse(int bank, int row, int bit)
295 {
296     int addr, addr_l, addr_h, reg_addr;
297
298     fuse_op_start();
299
300     addr = ((bank << 11) | (row << 3) | (bit & 0x7));
301     /* Set IIM Program Upper Address */
302     addr_h = (addr >> 8) & 0x000000FF;
303     /* Set IIM Program Lower Address */
304     addr_l = (addr & 0x000000FF);
305
306 #ifdef IIM_FUSE_DEBUG
307     diag_printf("%s: addr_h=0x%x, addr_l=0x%x\n",
308                 __FUNCTION__, addr_h, addr_l);
309 #endif
310     writel(addr_h, IIM_BASE_ADDR + IIM_UA_OFF);
311     writel(addr_l, IIM_BASE_ADDR + IIM_LA_OFF);
312     /* Start sensing */
313     writel(0x8, IIM_BASE_ADDR + IIM_FCTL_OFF);
314     if (poll_fuse_op_done(POLL_FUSE_SNSD) != 0) {
315         diag_printf("%s(bank: %d, row: %d, bit: %d failed\n",
316                     __FUNCTION__, bank, row, bit);
317     }
318     reg_addr = IIM_BASE_ADDR + IIM_SDAT_OFF;
319     diag_printf("fuses at (bank:%d, row:%d) = 0x%x\n", bank, row, readl(reg_addr));
320 }
321
322 void do_fuse_read(int argc, char *argv[])
323 {
324     int bank, row;
325
326     if (argc == 1) {
327         diag_printf("Useage: fuse_read <bank> <row>\n");
328         return;
329     } else if (argc == 3) {
330         if (!parse_num(*(&argv[1]), (unsigned long *)&bank, &argv[1], " ")) {
331                 diag_printf("Error: Invalid parameter\n");
332             return;
333         }
334         if (!parse_num(*(&argv[2]), (unsigned long *)&row, &argv[2], " ")) {
335                 diag_printf("Error: Invalid parameter\n");
336                 return;
337             }
338
339         diag_printf("Read fuse at bank:%d row:%d\n", bank, row);
340         sense_fuse(bank, row, 0);
341
342     } else {
343         diag_printf("Passing in wrong arguments: %d\n", argc);
344         diag_printf("Useage: fuse_read <bank> <row>\n");
345     }
346 }
347
348 /* Blow fuses based on the bank, row and bit positions (all 0-based)
349 */
350 static int fuse_blow(int bank,int row,int bit)
351 {
352     int addr, addr_l, addr_h, ret = -1;
353
354     fuse_op_start();
355
356     /* Disable IIM Program Protect */
357     writel(0xAA, IIM_BASE_ADDR + IIM_PREG_P_OFF);
358
359     addr = ((bank << 11) | (row << 3) | (bit & 0x7));
360     /* Set IIM Program Upper Address */
361     addr_h = (addr >> 8) & 0x000000FF;
362     /* Set IIM Program Lower Address */
363     addr_l = (addr & 0x000000FF);
364
365 #ifdef IIM_FUSE_DEBUG
366     diag_printf("blowing addr_h=0x%x, addr_l=0x%x\n", addr_h, addr_l);
367 #endif
368
369     writel(addr_h, IIM_BASE_ADDR + IIM_UA_OFF);
370     writel(addr_l, IIM_BASE_ADDR + IIM_LA_OFF);
371     /* Start Programming */
372     writel(0x71, IIM_BASE_ADDR + IIM_FCTL_OFF);
373     if (poll_fuse_op_done(POLL_FUSE_PRGD) == 0) {
374         ret = 0;
375     }
376
377     /* Enable IIM Program Protect */
378     writel(0x0, IIM_BASE_ADDR + IIM_PREG_P_OFF);
379     return ret;
380 }
381
382 /*
383  * This command is added for burning IIM fuses
384  */
385 RedBoot_cmd("fuse_read",
386             "read some fuses",
387             "<bank> <row>",
388             do_fuse_read
389            );
390
391 RedBoot_cmd("fuse_blow",
392             "blow some fuses",
393             "<bank> <row> <value>",
394             do_fuse_blow
395            );
396
397 #define         INIT_STRING              "12345678"
398 static char ready_to_blow[] = INIT_STRING;
399
400 void quick_itoa(u32 num, char *a)
401 {
402     int i, j, k;
403     for (i = 0; i <= 7; i++) {
404         j = (num >> (4 * i)) & 0xF;
405         k = (j < 10) ? '0' : ('a' - 0xa);
406         a[i] = j + k;
407     }
408 }
409
410 void do_fuse_blow(int argc, char *argv[])
411 {
412     int bank, row, value, i;
413
414     if (argc == 1) {
415         diag_printf("It is too dangeous for you to use this command.\n");
416         return;
417     } else if (argc == 2) {
418         if (strcasecmp(argv[1], "nandboot") == 0) {
419             quick_itoa(readl(EPIT_BASE_ADDR + EPITCNR), ready_to_blow);
420             diag_printf("%s\n", ready_to_blow);
421         }
422         return;
423     } else if (argc == 3) {
424         if (strcasecmp(argv[1], "nandboot") == 0 &&
425             strcasecmp(argv[2], ready_to_blow) == 0) {
426 #if defined(CYGPKG_HAL_ARM_MXC91131) || defined(CYGPKG_HAL_ARM_MX21) || defined(CYGPKG_HAL_ARM_MX27) || defined(CYGPKG_HAL_ARM_MX31) ||defined(CYGPKG_HAL_ARM_MX35) || defined(CYGPKG_HAL_ARM_MX25)
427             diag_printf("No need to blow any fuses for NAND boot on this platform\n\n");
428 #else
429 #error "Are you sure you want this?"
430             diag_printf("Ready to burn NAND boot fuses\n");
431             if (fuse_blow(0, 16, 1) != 0 || fuse_blow(0, 16, 7) != 0) {
432                 diag_printf("NAND BOOT fuse blown failed miserably ...\n");
433             } else {
434                 diag_printf("NAND BOOT fuse blown successfully ...\n");
435             }
436         } else {
437             diag_printf("Not ready: %s, %s\n", argv[1], argv[2]);
438 #endif
439         }
440     } else if (argc == 4) {
441         if (!parse_num(*(&argv[1]), (unsigned long *)&bank, &argv[1], " ")) {
442                 diag_printf("Error: Invalid parameter\n");
443                 return;
444         }
445         if (!parse_num(*(&argv[2]), (unsigned long *)&row, &argv[2], " ")) {
446                 diag_printf("Error: Invalid parameter\n");
447                 return;
448         }
449         if (!parse_num(*(&argv[3]), (unsigned long *)&value, &argv[3], " ")) {
450                 diag_printf("Error: Invalid parameter\n");
451                 return;
452         }
453
454         diag_printf("Blowing fuse at bank:%d row:%d value:%d\n",
455                     bank, row, value);
456         for (i = 0; i < 8; i++) {
457             if (((value >> i) & 0x1) == 0) {
458                 continue;
459             }
460             if (fuse_blow(bank, row, i) != 0) {
461                 diag_printf("fuse_blow(bank: %d, row: %d, bit: %d failed\n",
462                             bank, row, i);
463             } else {
464                 diag_printf("fuse_blow(bank: %d, row: %d, bit: %d successful\n",
465                             bank, row, i);
466             }
467         }
468         sense_fuse(bank, row, 0);
469
470     } else {
471         diag_printf("Passing in wrong arguments: %d\n", argc);
472     }
473     /* Reset to default string */
474     strcpy(ready_to_blow, INIT_STRING);;
475 }
476
477 /* precondition: m>0 and n>0.  Let g=gcd(m,n). */
478 int gcd(int m, int n)
479 {
480     int t;
481     while(m > 0) {
482         if(n > m) {t = m; m = n; n = t;} /* swap */
483         m -= n;
484     }
485     return n;
486 }
487