]> git.karo-electronics.de Git - karo-tx-redboot.git/blob - packages/hal/arm/mxc91221/var/v2_0/src/soc_misc.c
Initial revision
[karo-tx-redboot.git] / packages / hal / arm / mxc91221 / 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
62 // Most initialization has already been done before we get here.
63 // All we do here is set up the interrupt environment.
64 // FIXME: some of the stuff in hal_platform_setup could be moved here.
65
66 externC void plf_hardware_init(void);
67
68 #define IIM_PROD_REV_SH         4
69 #define IIM_PROD_REV_LEN        4
70 #define IIM_SREV_REV_SH         4
71 #define IIM_SREV_REV_LEN        4
72 #define PROD_SIGNATURE_MX31     0x1
73 #define PROD_SIGNATURE_MXC91331 0x4
74 #define PROD_SIGNATURE_MXC91321 0x6
75 #define PROD_SIGNATURE_MXC91231 0x8
76 #define PROD_SIGNATURE_MXC91131 0x10
77 #define PROD_SIGNATURE_MXC91221 0x5
78
79 #define PROD_SIGNATURE_SUPPORTED  PROD_SIGNATURE_MXC91221
80 #define CHIP_VERSION_NONE         0xFFFFFFFF      // invalid product ID
81 #define CHIP_VERSION_UNKNOWN      0xDEADBEEF      // invalid chip rev
82
83 #define MU_MEMORY_WRITE_OPCODE    1UL
84 #define MU_POLL_COUNTER_INIT      0x00100000
85 #define BP_PDC_DISABLE_VALUE      0x0
86 #define BP_PDC_LOCATION           0xFFF9C008
87
88 #define PART_NUMBER_OFFSET    (12)
89 #define MAJOR_NUMBER_OFFSET    (4)
90 #define MINOR_NUMBER_OFFSET    (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 -1.
99  */
100 static int read_system_rev(void)
101 {
102     int val;
103
104     val = readl(IIM_BASE_ADDR + IIM_PREV_OFF);
105
106     /* If the IIM doesn't contain valid product signature, return
107      * the lowest revision number */
108     if (MXC_GET_FIELD(val, IIM_PROD_REV_LEN, IIM_PROD_REV_SH) !=
109         PROD_SIGNATURE_SUPPORTED) {
110         return CHIP_VERSION_NONE;
111     } else {
112         system_rev = 0x91221 << PART_NUMBER_OFFSET;
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 static unsigned int mu_read(unsigned int idx, unsigned int *value)
119 {
120     unsigned int count = MU_POLL_COUNTER_INIT;
121     unsigned int mask = 1 << (27 - idx);
122     unsigned int addr = readl(MU_BASE_ADDR + 0x10 + (idx * 4));
123
124     /* Wait for MRFn bit to become set */
125     while (count-- && ((readl(MU_BASE_ADDR + 0x20) & mask) == 0));
126
127     /* Fail if counter expired */
128     if (count == ~0) {
129         return 1;
130     }
131     /* Read value from register */
132     *value = addr;
133
134     return 0;
135 }
136
137 static unsigned int mu_write(unsigned int idx, unsigned int value)
138 {
139     unsigned int count = MU_POLL_COUNTER_INIT;
140     unsigned int mask = 1 << (23 - idx);
141     unsigned int test;
142
143     /* Wait for MTEn bit to become set */
144     do {
145         test = (readl(MU_BASE_ADDR + 0x20) & mask);
146     } while (count-- && !test);
147
148     /* Fail if counter expired */
149     if (count == ~0)
150         return 1;
151
152     /* Write value to register */
153     writel(value, MU_BASE_ADDR + (idx * 0x4));
154
155     return 0;
156 }
157
158 static int clear_bp_wdog_pde(unsigned int dst, unsigned int num)
159 {
160     unsigned int index = 0;
161     unsigned int response;
162     unsigned int count = num;
163
164     /* Write command and destination address */
165     if (mu_write(index++, (num << 16) | MU_MEMORY_WRITE_OPCODE)
166         || mu_write(index++, dst)) {
167         return 1;
168     }
169
170     /* Write words from source, wrapping around 4 MU registers */
171     while (num--)
172     {
173         if (mu_write(index++, BP_PDC_DISABLE_VALUE)) return 1;
174         index = index % 4;
175     }
176
177     /* Read response and check */
178     if (mu_read(0, &response)
179         || (count != (response >> 16))
180         || (MU_MEMORY_WRITE_OPCODE != (response & 0xFF))
181         || (0 != ((response >> 8) & 0xFF))) {
182         return 1;
183     }
184
185     return 0;
186 }
187
188 char HAL_PLATFORM_EXTRA[20] = "PASS 1.0 [x32 DDR]";
189
190 void hal_hardware_init(void)
191 {
192     volatile unsigned int esdmisc = readl(ESDCTL_BASE + 0x10);
193     volatile unsigned int esdctl0 = readl(ESDCTL_BASE);
194     int ver = read_system_rev();
195
196     find_correct_chip = ver;
197
198     if (ver != CHIP_VERSION_NONE) {
199         /* Valid product revision found. Check actual silicon rev and
200          * NOT use the version from the ROM code. */
201         if (MXC_GET_FIELD(ver, IIM_PROD_REV_LEN, IIM_PROD_REV_SH) ==
202             CHIP_REV_1_0) {
203             HAL_PLATFORM_EXTRA[5] = '1';
204             system_rev |= 1 << MAJOR_NUMBER_OFFSET;
205             system_rev |= 0 << MINOR_NUMBER_OFFSET;
206         } else {
207             HAL_PLATFORM_EXTRA[5] = 'x';
208             HAL_PLATFORM_EXTRA[7] = 'x';
209             system_rev |= 1 << MAJOR_NUMBER_OFFSET;
210             system_rev |= 0 << MINOR_NUMBER_OFFSET;
211             find_correct_chip = CHIP_VERSION_UNKNOWN;
212         }
213     }
214
215     if ((esdmisc & 0x4) == 0) {
216         HAL_PLATFORM_EXTRA[14] = 'S';
217     }
218     if ((esdctl0 & 0x30000) != 0x20000) {
219         HAL_PLATFORM_EXTRA[11] = '1';
220         HAL_PLATFORM_EXTRA[12] = '6';
221     }
222
223     // Mask all interrupts
224     writel(0xFFFFFFFF, AVIC_NIMASK);
225
226     // Make all interrupts do IRQ and not FIQ
227     // FIXME: Change this if you use FIQs.
228     writel(0, AVIC_INTTYPEH);
229     writel(0, AVIC_INTTYPEL);
230
231     // Enable caches
232     HAL_ICACHE_ENABLE();
233     HAL_DCACHE_ENABLE();
234
235     // enable EPIT and start it with 32KHz input clock
236     writel(0x00010000, EPIT_BASE_ADDR + EPITCR);
237
238     // make sure reset is complete
239     while ((readl(EPIT_BASE_ADDR + EPITCR) & 0x10000) != 0) {
240     }
241
242     writel(0x030E0002, EPIT_BASE_ADDR + EPITCR);
243     writel(0x030E0003, EPIT_BASE_ADDR + EPITCR);
244
245     writel(0, EPIT_BASE_ADDR + EPITCMPR);  // always compare with 0
246
247     // disable PDE bit inside AP WDOG
248     writew(0x0 , WDOG_BASE_ADDR + 0x8);
249     // disable PDE bit inside BP WDOG
250     clear_bp_wdog_pde(BP_PDC_LOCATION, 1);
251     if ((readw(WDOG_BASE_ADDR) & 4) != 0) {
252         // increase the WDOG timeout value to the max
253         writew(readw(WDOG_BASE_ADDR) | 0xFF00, WDOG_BASE_ADDR);
254     }
255
256     // Perform any platform specific initializations
257     plf_hardware_init();
258
259     // Set up eCos/ROM interfaces
260     hal_if_init();
261 }
262
263 // -------------------------------------------------------------------------
264 void hal_clock_initialize(cyg_uint32 period)
265 {
266 }
267
268 // This routine is called during a clock interrupt.
269
270 // Define this if you want to ensure that the clock is perfect (i.e. does
271 // not drift).  One reason to leave it turned off is that it costs some
272 // us per system clock interrupt for this maintenance.
273 #undef COMPENSATE_FOR_CLOCK_DRIFT
274
275 void hal_clock_reset(cyg_uint32 vector, cyg_uint32 period)
276 {
277 }
278
279 // Read the current value of the clock, returning the number of hardware
280 // "ticks" that have occurred (i.e. how far away the current value is from
281 // the start)
282
283 // Note: The "contract" for this function is that the value is the number
284 // of hardware clocks that have happened since the last interrupt (i.e.
285 // when it was reset).  This value is used to measure interrupt latencies.
286 // However, since the hardware counter runs freely, this routine computes
287 // the difference between the current clock period and the number of hardware
288 // ticks left before the next timer interrupt.
289 void hal_clock_read(cyg_uint32 *pvalue)
290 {
291 }
292
293 // This is to cope with the test read used by tm_basic with
294 // CYGVAR_KERNEL_COUNTERS_CLOCK_LATENCY defined; we read the count ASAP
295 // in the ISR, *before* resetting the clock.  Which returns 1tick +
296 // latency if we just use plain hal_clock_read().
297 void hal_clock_latency(cyg_uint32 *pvalue)
298 {
299 }
300
301 unsigned int hal_timer_count(void)
302 {
303     return (0xFFFFFFFF - readl(EPIT_BASE_ADDR + EPITCNR));
304 }
305
306 #define WDT_MAGIC_1             0x5555
307 #define WDT_MAGIC_2             0xAAAA
308 #define MXC_WDT_WSR             0x2
309
310 static unsigned int led_on = 0;
311 //
312 // Delay for some number of micro-seconds
313 //
314 void hal_delay_us(unsigned int usecs)
315 {
316     /*
317      * This causes overflow.
318      * unsigned int delayCount = (usecs * 32768) / 1000000;
319      * So use the following one instead
320      */
321     unsigned int delayCount = (usecs * 512) / 15625;
322
323     if (delayCount == 0) {
324         return;
325     }
326
327     // issue the service sequence instructions
328     if ((readw(WDOG_BASE_ADDR) & 4) != 0) {
329         writew(WDT_MAGIC_1, WDOG_BASE_ADDR + MXC_WDT_WSR);
330         writew(WDT_MAGIC_2, WDOG_BASE_ADDR + MXC_WDT_WSR);
331     }
332
333     writel(0x01, EPIT_BASE_ADDR + EPITSR); // clear the compare status bit
334
335     writel(delayCount, EPIT_BASE_ADDR + EPITLR);
336
337     while ((0x1 & readl(EPIT_BASE_ADDR + EPITSR)) == 0); // return until compare bit is set
338     if ((++led_on % 2000) == 0)
339         BOARD_DEBUG_LED(0);
340 }
341
342 // -------------------------------------------------------------------------
343
344 // This routine is called to respond to a hardware interrupt (IRQ).  It
345 // should interrogate the hardware and return the IRQ vector number.
346 int hal_IRQ_handler(void)
347 {
348 #ifdef HAL_EXTENDED_IRQ_HANDLER
349     cyg_uint32 index;
350
351     // Use platform specific IRQ handler, if defined
352     // Note: this macro should do a 'return' with the appropriate
353     // interrupt number if such an extended interrupt exists.  The
354     // assumption is that the line after the macro starts 'normal' processing.
355     HAL_EXTENDED_IRQ_HANDLER(index);
356 #endif
357
358     return CYGNUM_HAL_INTERRUPT_NONE; // This shouldn't happen!
359 }
360
361 //
362 // Interrupt control
363 //
364
365 void hal_interrupt_mask(int vector)
366 {
367 //        diag_printf("6hal_interrupt_mask(vector=%d) \n", vector);
368 #ifdef HAL_EXTENDED_INTERRUPT_MASK
369     // Use platform specific handling, if defined
370     // Note: this macro should do a 'return' for "extended" values of 'vector'
371     // Normal vectors are handled by code subsequent to the macro call.
372     HAL_EXTENDED_INTERRUPT_MASK(vector);
373 #endif
374 }
375
376 void hal_interrupt_unmask(int vector)
377 {
378 //        diag_printf("7hal_interrupt_unmask(vector=%d) \n", vector);
379
380 #ifdef HAL_EXTENDED_INTERRUPT_UNMASK
381     // Use platform specific handling, if defined
382     // Note: this macro should do a 'return' for "extended" values of 'vector'
383     // Normal vectors are handled by code subsequent to the macro call.
384     HAL_EXTENDED_INTERRUPT_UNMASK(vector);
385 #endif
386 }
387
388 void hal_interrupt_acknowledge(int vector)
389 {
390
391 //        diag_printf("8hal_interrupt_acknowledge(vector=%d) \n", vector);
392 #ifdef HAL_EXTENDED_INTERRUPT_UNMASK
393     // Use platform specific handling, if defined
394     // Note: this macro should do a 'return' for "extended" values of 'vector'
395     // Normal vectors are handled by code subsequent to the macro call.
396     HAL_EXTENDED_INTERRUPT_ACKNOWLEDGE(vector);
397 #endif
398 }
399
400 void hal_interrupt_configure(int vector, int level, int up)
401 {
402
403 #ifdef HAL_EXTENDED_INTERRUPT_CONFIGURE
404     // Use platform specific handling, if defined
405     // Note: this macro should do a 'return' for "extended" values of 'vector'
406     // Normal vectors are handled by code subsequent to the macro call.
407     HAL_EXTENDED_INTERRUPT_CONFIGURE(vector, level, up);
408 #endif
409 }
410
411 void hal_interrupt_set_level(int vector, int level)
412 {
413
414 #ifdef HAL_EXTENDED_INTERRUPT_SET_LEVEL
415     // Use platform specific handling, if defined
416     // Note: this macro should do a 'return' for "extended" values of 'vector'
417     // Normal vectors are handled by code subsequent to the macro call.
418     HAL_EXTENDED_INTERRUPT_SET_LEVEL(vector, level);
419 #endif
420
421     // Interrupt priorities are not configurable.
422 }
423
424 static void check_correct_chip(void)
425 {
426     if (find_correct_chip == CHIP_VERSION_UNKNOWN) {
427         diag_printf("Unrecognized chip version: 0x%x!!!\n", read_system_rev());
428         diag_printf("Assuming chip version=0x%x\n", system_rev);
429     } else if (find_correct_chip == CHIP_VERSION_NONE) {
430         diag_printf("Unrecognized chip: 0x%x!!!\n", readl(IIM_BASE_ADDR + IIM_PREV_OFF));
431     }
432 }
433
434 RedBoot_init(check_correct_chip, RedBoot_INIT_LAST);