Bugfix Release STK5 2010-10-04
[karo-tx-redboot.git] / packages / hal / arm / mx25 / var / v2_0 / src / soc_misc.c
1 //==========================================================================
2 //
3 //      soc_misc.c
4 //
5 //      HAL misc board support code
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
42 #include <redboot.h>
43 #include <pkgconf/hal.h>
44 #include <pkgconf/system.h>
45 #include CYGBLD_HAL_PLATFORM_H
46
47 #include <cyg/infra/cyg_type.h>                 // base types
48 #include <cyg/infra/cyg_trac.h>                 // tracing macros
49 #include <cyg/infra/cyg_ass.h>                  // assertion macros
50
51 #include <cyg/hal/hal_misc.h>                   // Size constants
52 #include <cyg/hal/hal_io.h>                             // IO macros
53 #include <cyg/hal/hal_arch.h>                   // Register state info
54 #include <cyg/hal/hal_diag.h>
55 #include <cyg/hal/hal_intr.h>                   // Interrupt names
56 #include <cyg/hal/hal_cache.h>                  // Cache control
57 #include <cyg/hal/hal_soc.h>                    // Hardware definitions
58 #include <cyg/hal/hal_mm.h>                             // MMap table definitions
59
60 #include <cyg/infra/diag.h>                             // diag_printf
61 #include <cyg/io/imx_nfc.h>
62
63 // Most initialization has already been done before we get here.
64 // All we do here is set up the interrupt environment.
65 // FIXME: some of the stuff in hal_platform_setup could be moved here.
66
67 externC void plf_hardware_init(void);
68
69 #define IIM_PROD_REV_SH                 3
70 #define IIM_PROD_REV_LEN                5
71 #define IIM_SREV_REV_SH                 4
72 #define IIM_SREV_REV_LEN                4
73
74 #define PROD_SIGNATURE_MX25             0x1F
75
76 #define PROD_SIGNATURE_SUPPORTED_1      PROD_SIGNATURE_MX25
77
78 #define CHIP_VERSION_NONE                       0xFFFFFFFF              // invalid product ID
79 #define CHIP_VERSION_UNKNOWN            0xDEADBEEF              // invalid chip rev
80
81 #define PART_NUMBER_OFFSET                      12
82 #define MAJOR_NUMBER_OFFSET                     4
83 #define MINOR_NUMBER_OFFSET                     0
84
85 /*
86  * System_rev will have the following format
87  * 31-12 = part # (0x31, 0x32, 0x27, 0x91131, 0x91321, 0x35, etc)
88  * 11-8 = unused
89  * 7-4 = major (1.y)
90  * 3-0 = minor (x.0)
91  */
92 unsigned int system_rev = CHIP_REV_1_0;
93 static int find_correct_chip;
94
95 /*
96  * This functions reads the IIM module and returns the system revision number.
97  * It returns the IIM silicon revision reg value if valid product rev is found.
98  * Otherwise, it returns CHIP_VERSION_NONE.
99  */
100 static int read_system_rev(void)
101 {
102         int val;
103
104         val = readl(IIM_BASE_ADDR + IIM_PREV_OFF);
105
106         system_rev = 0x25 << PART_NUMBER_OFFSET; /* For MX25 Platform*/
107         /* If the IIM doesn't contain a valid product signature, return
108          * the lowest revision number */
109         if ((MXC_GET_FIELD(val, IIM_PROD_REV_LEN, IIM_PROD_REV_SH) !=
110                         PROD_SIGNATURE_SUPPORTED_1)) {
111                 return CHIP_VERSION_NONE;
112         }
113
114         /* Now trying to retrieve the silicon rev from IIM's SREV register */
115         return readl(IIM_BASE_ADDR + IIM_SREV_OFF);
116 }
117
118 extern nfc_setup_func_t *nfc_setup;
119 unsigned int mxc_nfc_soc_setup(unsigned int pg_sz, unsigned int io_sz,
120                                                         unsigned int is_mlc, unsigned int num_of_chips);
121 void hal_hardware_init(void)
122 {
123         int ver;
124
125         ver = read_system_rev();
126         find_correct_chip = ver;
127
128         if (ver != CHIP_VERSION_NONE) {
129                 /* Valid product revision found. Check actual silicon rev from the ROM code. */
130                 if (ver == 0x0) {
131                         HAL_PLATFORM_EXTRA[5] = '1';
132                         HAL_PLATFORM_EXTRA[7] = '0';
133                         system_rev |= 1 << MAJOR_NUMBER_OFFSET;
134                         system_rev |= 0 << MINOR_NUMBER_OFFSET;
135                 } else if (ver == 0x1) {
136                         HAL_PLATFORM_EXTRA[5] = '1';
137                         HAL_PLATFORM_EXTRA[7] = '1';
138                         system_rev |= 1 << MAJOR_NUMBER_OFFSET;
139                         system_rev |= 1 << MINOR_NUMBER_OFFSET;
140                 } else if (ver == 0x2) {
141                         HAL_PLATFORM_EXTRA[5] = '1';
142                         HAL_PLATFORM_EXTRA[7] = '1';
143                         system_rev |= 1 << MAJOR_NUMBER_OFFSET;
144                         system_rev |= 2 << MINOR_NUMBER_OFFSET;
145                 } else {
146                         HAL_PLATFORM_EXTRA[5] = '-';
147                         HAL_PLATFORM_EXTRA[7] = '-';
148                         system_rev |= 1 << MAJOR_NUMBER_OFFSET;
149                         system_rev |= 0 << MINOR_NUMBER_OFFSET;
150                         find_correct_chip = CHIP_VERSION_UNKNOWN;
151                 }
152         }
153
154         // Mask all interrupts
155         writel(0xFFFFFFFF, ASIC_NIMASK);
156
157         // Make all interrupts do IRQ and not FIQ
158         // FIXME: Change this if you use FIQs.
159         writel(0, ASIC_INTTYPEH);
160         writel(0, ASIC_INTTYPEL);
161
162         // Enable caches
163         HAL_ICACHE_ENABLE();
164         HAL_DCACHE_ENABLE();
165
166         // enable EPIT and start it with 32KHz input clock
167         writel(0x00010000, EPIT_BASE_ADDR + EPITCR);
168
169         // make sure reset is complete
170         while ((readl(EPIT_BASE_ADDR + EPITCR) & 0x10000) != 0) {
171         }
172
173         writel(0x030E0002, EPIT_BASE_ADDR + EPITCR);
174         writel(0x030E0003, EPIT_BASE_ADDR + EPITCR);
175
176         writel(0, EPIT_BASE_ADDR + EPITCMPR);  // always compare with 0
177
178         if ((readw(WDOG_BASE_ADDR) & 4) != 0) {
179                 // increase the WDOG timeout value to the max
180                 writew(readw(WDOG_BASE_ADDR) | 0xFF00, WDOG_BASE_ADDR);
181         }
182
183         // Perform any platform specific initializations
184         plf_hardware_init();
185
186         // Set up eCos/ROM interfaces
187         hal_if_init();
188
189         nfc_setup = (nfc_setup_func_t*)mxc_nfc_soc_setup;
190 }
191
192 // -------------------------------------------------------------------------
193 void hal_clock_initialize(cyg_uint32 period)
194 {
195 }
196
197 // This routine is called during a clock interrupt.
198
199 // Define this if you want to ensure that the clock is perfect (i.e. does
200 // not drift).  One reason to leave it turned off is that it costs some
201 // us per system clock interrupt for this maintenance.
202 #undef COMPENSATE_FOR_CLOCK_DRIFT
203
204 void hal_clock_reset(cyg_uint32 vector, cyg_uint32 period)
205 {
206 }
207
208 // Read the current value of the clock, returning the number of hardware
209 // "ticks" that have occurred (i.e. how far away the current value is from
210 // the start)
211
212 // Note: The "contract" for this function is that the value is the number
213 // of hardware clocks that have happened since the last interrupt (i.e.
214 // when it was reset).  This value is used to measure interrupt latencies.
215 // However, since the hardware counter runs freely, this routine computes
216 // the difference between the current clock period and the number of hardware
217 // ticks left before the next timer interrupt.
218 void hal_clock_read(cyg_uint32 *pvalue)
219 {
220 }
221
222 // This is to cope with the test read used by tm_basic with
223 // CYGVAR_KERNEL_COUNTERS_CLOCK_LATENCY defined; we read the count ASAP
224 // in the ISR, *before* resetting the clock.  Which returns 1tick +
225 // latency if we just use plain hal_clock_read().
226 void hal_clock_latency(cyg_uint32 *pvalue)
227 {
228 }
229
230 unsigned int hal_timer_count(void)
231 {
232         return 0 - readl(EPIT_BASE_ADDR + EPITCNR);
233 }
234
235 #define WDT_MAGIC_1                             0x5555
236 #define WDT_MAGIC_2                             0xAAAA
237 #define MXC_WDT_WSR                             0x2
238
239 unsigned int i2c_base_addr[] = {
240         I2C_BASE_ADDR,
241         I2C2_BASE_ADDR,
242         I2C3_BASE_ADDR
243 };
244 unsigned int i2c_num = 3;
245
246 static unsigned int led_on = 0;
247 //
248 // Delay for some number of microseconds
249 //
250 void hal_delay_us(unsigned int usecs)
251 {
252         /*
253          * This causes overflow.
254          * unsigned int delayCount = (usecs * 32000) / 1000000;
255          * So use the following one instead
256          */
257         unsigned int delayCount = (usecs * 512) / 16000;
258
259         if (delayCount == 0) {
260                 return;
261         }
262
263         // issue the service sequence instructions
264         if ((readw(WDOG_BASE_ADDR) & 4) != 0) {
265                 writew(WDT_MAGIC_1, WDOG_BASE_ADDR + MXC_WDT_WSR);
266                 writew(WDT_MAGIC_2, WDOG_BASE_ADDR + MXC_WDT_WSR);
267         }
268
269         writel(0x01, EPIT_BASE_ADDR + EPITSR); // clear the compare status bit
270
271         writel(delayCount, EPIT_BASE_ADDR + EPITLR);
272
273         while ((0x1 & readl(EPIT_BASE_ADDR + EPITSR)) == 0); // return until compare bit is set
274         if ((++led_on % 2000) == 0)
275                 BOARD_DEBUG_LED(0);
276 }
277
278 // -------------------------------------------------------------------------
279
280 // This routine is called to respond to a hardware interrupt (IRQ).  It
281 // should interrogate the hardware and return the IRQ vector number.
282 int hal_IRQ_handler(void)
283 {
284 #ifdef HAL_EXTENDED_IRQ_HANDLER
285         cyg_uint32 index;
286
287         // Use platform specific IRQ handler, if defined
288         // Note: this macro should do a 'return' with the appropriate
289         // interrupt number if such an extended interrupt exists.  The
290         // assumption is that the line after the macro starts 'normal' processing.
291         HAL_EXTENDED_IRQ_HANDLER(index);
292 #endif
293
294         return CYGNUM_HAL_INTERRUPT_NONE; // This shouldn't happen!
295 }
296
297 //
298 // Interrupt control
299 //
300
301 void hal_interrupt_mask(int vector)
302 {
303 //    diag_printf("6hal_interrupt_mask(vector=%d) \n", vector);
304 #ifdef HAL_EXTENDED_INTERRUPT_MASK
305         // Use platform specific handling, if defined
306         // Note: this macro should do a 'return' for "extended" values of 'vector'
307         // Normal vectors are handled by code subsequent to the macro call.
308         HAL_EXTENDED_INTERRUPT_MASK(vector);
309 #endif
310 }
311
312 void hal_interrupt_unmask(int vector)
313 {
314 //    diag_printf("7hal_interrupt_unmask(vector=%d) \n", vector);
315
316 #ifdef HAL_EXTENDED_INTERRUPT_UNMASK
317         // Use platform specific handling, if defined
318         // Note: this macro should do a 'return' for "extended" values of 'vector'
319         // Normal vectors are handled by code subsequent to the macro call.
320         HAL_EXTENDED_INTERRUPT_UNMASK(vector);
321 #endif
322 }
323
324 void hal_interrupt_acknowledge(int vector)
325 {
326
327 //    diag_printf("8hal_interrupt_acknowledge(vector=%d) \n", vector);
328 #ifdef HAL_EXTENDED_INTERRUPT_UNMASK
329         // Use platform specific handling, if defined
330         // Note: this macro should do a 'return' for "extended" values of 'vector'
331         // Normal vectors are handled by code subsequent to the macro call.
332         HAL_EXTENDED_INTERRUPT_ACKNOWLEDGE(vector);
333 #endif
334 }
335
336 void hal_interrupt_configure(int vector, int level, int up)
337 {
338
339 #ifdef HAL_EXTENDED_INTERRUPT_CONFIGURE
340         // Use platform specific handling, if defined
341         // Note: this macro should do a 'return' for "extended" values of 'vector'
342         // Normal vectors are handled by code subsequent to the macro call.
343         HAL_EXTENDED_INTERRUPT_CONFIGURE(vector, level, up);
344 #endif
345 }
346
347 void hal_interrupt_set_level(int vector, int level)
348 {
349
350 #ifdef HAL_EXTENDED_INTERRUPT_SET_LEVEL
351         // Use platform specific handling, if defined
352         // Note: this macro should do a 'return' for "extended" values of 'vector'
353         // Normal vectors are handled by code subsequent to the macro call.
354         HAL_EXTENDED_INTERRUPT_SET_LEVEL(vector, level);
355 #endif
356
357         // Interrupt priorities are not configurable.
358 }
359
360 unsigned int mxc_nfc_soc_setup(unsigned int pg_sz, unsigned int io_sz, unsigned int is_mlc,
361                                                            unsigned int num_of_chips)
362 {
363         unsigned int tmp ;
364         if (is_mlc) {
365                 tmp = readw(NAND_REG_BASE + NAND_FLASH_CONFIG1_REG_OFF) | (1 << 8);
366         } else {
367                 tmp = readw(NAND_REG_BASE + NAND_FLASH_CONFIG1_REG_OFF) & ~(1 << 8);
368         }
369
370         writew(tmp, NAND_REG_BASE + NAND_FLASH_CONFIG1_REG_OFF);
371         tmp = readl(CCM_BASE_ADDR + CLKCTL_RCSR);
372         if (io_sz == 16) {
373                 tmp |= (1 << 14);
374         } else {
375                 tmp &= ~(1 << 14);
376         }
377
378         tmp &= ~(3<<8);
379         switch (pg_sz) {
380         case 2048:
381                 tmp |= (1<<8);
382                 break;
383         case 4096:
384                 tmp |= (1<<9);
385                 break;
386         }
387
388         writel(tmp, CCM_BASE_ADDR + CLKCTL_RCSR);
389         return MXC_NFC_V1_1;
390 }
391
392 #define WDOG_WRSR       ((CYG_WORD16 *)(WDOG_BASE_ADDR + 0x4))
393 #define CRM_RCSR        ((CYG_WORD32 *)(CCM_BASE_ADDR + 0x28))
394
395 static void check_reset_source(void)
396 {
397 #if 1
398         char *reset_cause = "UNKNOWN";
399         CYG_WORD16 wrsr;
400         CYG_WORD32 rcsr;
401
402         HAL_READ_UINT32(CRM_RCSR, rcsr);
403         HAL_READ_UINT16(WDOG_WRSR, wrsr);
404         rcsr &= 0x0f;
405         if (rcsr == 0) {
406                 reset_cause = "POWER_ON RESET";
407         } else if (rcsr == 1) {
408                 reset_cause = "EXTERNAL RESET";
409         } else if (rcsr & (1 << 3)) {
410                 reset_cause = "JTAG RESET";
411         } else if (rcsr & (1 << 2)) {
412                 reset_cause = "SOFT RESET";
413         } else if (rcsr & (1 << 1)) {
414                 if (wrsr & (1 << 0)) {
415                         reset_cause = "SOFTWARE RESET";
416                 } else if (wrsr & (1 << 1)) {
417                         reset_cause = "WATCHDOG TIMEOUT";
418                 }
419         } else {
420                 diag_printf("Unknown RESET cause: RCSR=0x%08x WRSR=0x%04x\n", rcsr, wrsr);
421                 return;
422         }
423         diag_printf("Last RESET cause: %s\n", reset_cause);
424 #else
425         unsigned int rest = readl(CCM_BASE_ADDR + CLKCTL_RCSR) & 0xF;
426
427         if (rest == 0)
428                 diag_printf("hardware reset by POR\n");
429         else if (rest == 1)
430                 diag_printf("hardware reset by Board reset signal\n");
431         else if (rest & 2)
432                 diag_printf("hardware reset by WDOG\n");
433         else if (rest & 4)
434                 diag_printf("hardware reset by SOFT RESET\n");
435         else if (rest & 8)
436                 diag_printf("hardware reset by JTAG SW RESET\n");
437         else
438                 diag_printf("hardware reset by unknown source (REST=%x)\n", rest);
439 #endif
440 }
441
442 RedBoot_init(check_reset_source, RedBoot_INIT_LAST);
443
444 static void check_correct_chip(void)
445 {
446         if (find_correct_chip == CHIP_VERSION_UNKNOWN) {
447                 diag_printf("Unrecognized chip version: 0x%x!!!\n", read_system_rev());
448                 diag_printf("Assuming chip version=0x%x\n", system_rev);
449         } else if (find_correct_chip == CHIP_VERSION_NONE) {
450                 diag_printf("Unrecognized chip: 0x%x!!!\n", readl(IIM_BASE_ADDR + IIM_PREV_OFF));
451         }
452 }
453
454 RedBoot_init(check_correct_chip, RedBoot_INIT_LAST);