]> git.kernelconcepts.de Git - karo-tx-redboot.git/blob - packages/hal/arm/xscale/pxa2x0/v2_0/src/pxa2x0_misc.c
unified MX27, MX25, MX37 trees
[karo-tx-redboot.git] / packages / hal / arm / xscale / pxa2x0 / v2_0 / src / pxa2x0_misc.c
1 //==========================================================================
2 //
3 //      pxa2x0_misc.c
4 //
5 //      HAL misc board support code for Intel PXA2X0
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 // Copyright (C) 2003 Gary Thomas
13 //
14 // eCos is free software; you can redistribute it and/or modify it under
15 // the terms of the GNU General Public License as published by the Free
16 // Software Foundation; either version 2 or (at your option) any later version.
17 //
18 // eCos is distributed in the hope that it will be useful, but WITHOUT ANY
19 // WARRANTY; without even the implied warranty of MERCHANTABILITY or
20 // FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
21 // for more details.
22 //
23 // You should have received a copy of the GNU General Public License along
24 // with eCos; if not, write to the Free Software Foundation, Inc.,
25 // 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
26 //
27 // As a special exception, if other files instantiate templates or use macros
28 // or inline functions from this file, or you compile this file and link it
29 // with other works to produce a work based on this file, this file does not
30 // by itself cause the resulting work to be covered by the GNU General Public
31 // License. However the source code for this file must still be made available
32 // in accordance with section (3) of the GNU General Public License.
33 //
34 // This exception does not invalidate any other reasons why a work based on
35 // this file might be covered by the GNU General Public License.
36 //
37 // Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
38 // at http://sources.redhat.com/ecos/ecos-license/
39 // -------------------------------------------
40 //####ECOSGPLCOPYRIGHTEND####
41 //==========================================================================
42 //#####DESCRIPTIONBEGIN####
43 //
44 // Author(s):    <knud.woehler@microplex.de>
45 // Date:         2002-09-03
46 //
47 //####DESCRIPTIONEND####
48 //
49 //========================================================================*/
50
51 #include <pkgconf/hal.h>
52 #include <pkgconf/system.h>
53 #include CYGBLD_HAL_PLATFORM_H
54 #include <cyg/infra/cyg_type.h>
55 #include <cyg/infra/cyg_trac.h>
56 #include <cyg/infra/cyg_ass.h>
57 #include <cyg/hal/hal_misc.h>
58 #include <cyg/hal/hal_io.h>
59 #include <cyg/hal/hal_stub.h>
60 #include <cyg/hal/hal_arch.h>
61 #include <cyg/hal/hal_diag.h>
62 #include <cyg/hal/hal_intr.h>
63 #include <cyg/hal/hal_cache.h>
64 #include <cyg/hal/hal_pxa2x0.h>
65 #include <cyg/hal/hal_mm.h>
66 #include <cyg/infra/diag.h>
67
68
69 // Initialize the interrupt environment
70 externC void plf_hardware_init(void);
71
72 void hal_hardware_init(void)
73 {
74     hal_xscale_core_init();
75
76     *PXA2X0_ICMR = 0;           // IRQ Mask
77     *PXA2X0_ICLR = 0;           // Route interrupts to IRQ
78     *PXA2X0_ICCR = 1;
79
80     *PXA2X0_GRER0 = 0;          // Disable rising edge detect
81     *PXA2X0_GRER1 = 0;
82     *PXA2X0_GRER2 = 0;
83
84     *PXA2X0_GFER0 = 0;          // Disable falling edge detect
85     *PXA2X0_GFER1 = 0;
86     *PXA2X0_GFER2 = 0;
87
88 #if defined(CYGOPT_HAL_ARM_XSCALE_PXA2X0_VARIANT_PXA25X)
89     *PXA2X0_GEDR0 = 0xffffffff; // Clear edge detect status
90     *PXA2X0_GEDR1 = 0xffffffff;
91     *PXA2X0_GEDR2 = 0x0001ffff;
92 #elif defined(CYGOPT_HAL_ARM_XSCALE_PXA2X0_VARIANT_PXA27X)
93     *PXA2X0_ICMR2 = 0;
94     *PXA2X0_ICLR2 = 0;
95
96     *PXA2X0_GRER3 = 0;
97     *PXA2X0_GFER3 = 0;
98
99     *PXA2X0_GEDR0 = 0xfffff71b;
100     *PXA2X0_GEDR1 = 0xffffffff;
101     *PXA2X0_GEDR2 = 0xffffffff;
102     *PXA2X0_GEDR3 = 0x1fffffff;
103 #endif
104
105     plf_hardware_init();        // Perform any platform specific initializations
106
107     *PXA2X0_OSCR = 0;           // Let the "OS" counter run
108     *PXA2X0_OSMR0 = 0;
109
110 #ifdef CYGSEM_HAL_ENABLE_DCACHE_ON_STARTUP
111     HAL_DCACHE_ENABLE();        // Enable caches
112 #endif
113 #ifdef CYGSEM_HAL_ENABLE_ICACHE_ON_STARTUP
114     HAL_ICACHE_ENABLE();
115 #endif
116 }
117
118 //
119 // GPIO support functions
120 //
121 void
122 _pxa2x0_set_GPIO_mode(int bit, int mode, int dir)
123 {
124     int bank = bit / 32;
125     unsigned volatile long *gpdr, *gafr;
126
127     gpdr = &PXA2X0_GPDR0[bank];
128     gafr = &PXA2X0_GAFR0_L[(bit&0x30)>>4];
129     bit %= 32;
130     // Data direction registers have 1 bit per GPIO
131     *gpdr = (*gpdr & ~(1<<bit)) | (dir<<bit);
132     // Alternate function regusters have 2 bits per GPIO
133     bit = (bit & 0x0F) * 2;
134     *gafr = (*gafr & ~(3<<bit)) | (mode<<bit);
135 }
136
137
138 // Initialize the clock
139 static cyg_uint32  clock_period;
140
141 void hal_clock_initialize(cyg_uint32 period)
142 {
143         *PXA2X0_OSMR0 = period;                                 // Load match value
144         clock_period = period;
145     
146         *PXA2X0_OSCR = 0;                                               // Start the counter
147     *PXA2X0_OSSR = PXA2X0_OSSR_TIMER0;          // Clear any pending interrupt
148     *PXA2X0_OIER |= PXA2X0_OIER_TIMER0;         // Enable timer 0 interrupt
149
150     HAL_INTERRUPT_UNMASK( CYGNUM_HAL_INTERRUPT_TIMER0 );        // Unmask timer 0 interrupt
151 }
152
153 // This routine is called during a clock interrupt.
154 void hal_clock_reset(cyg_uint32 vector, cyg_uint32 period)
155 {
156     *PXA2X0_OSMR0 = *PXA2X0_OSCR + period;      // Load new match value
157     *PXA2X0_OSSR = PXA2X0_OSSR_TIMER0;          // Clear any pending interrupt
158 }
159
160 // Read the current value of the clock, returning the number of hardware
161 // "ticks" that have occurred (i.e. how far away the current value is from
162 // the start)
163
164 // Note: The "contract" for this function is that the value is the number
165 // of hardware clocks that have happened since the last interrupt (i.e.
166 // when it was reset).  This value is used to measure interrupt latencies.
167 // However, since the hardware counter runs freely, this routine computes
168 // the difference between the current clock period and the number of hardware
169 // ticks left before the next timer interrupt.
170 void hal_clock_read(cyg_uint32 *pvalue)
171 {
172     int orig;
173     HAL_DISABLE_INTERRUPTS(orig);
174     *pvalue = clock_period + *PXA2X0_OSCR - *PXA2X0_OSMR0;
175     HAL_RESTORE_INTERRUPTS(orig);
176 }
177
178 // Delay for some number of micro-seconds
179 void hal_delay_us(cyg_int32 usecs)
180 {
181 #if defined(CYGOPT_HAL_ARM_XSCALE_PXA2X0_VARIANT_PXA25X)
182 #  define NSECS_PER_TICK 271267 /* 3.6865 MHz clock */
183 #elif defined(CYGOPT_HAL_ARM_XSCALE_PXA2X0_VARIANT_PXA27X)
184 #  define NSECS_PER_TICK 307692 /* 3.25 MHz clock */
185 #endif
186
187     cyg_uint32 val = 0;
188     cyg_uint32 prev = *PXA2X0_OSCR;
189     while (usecs-- > 0) {
190         while (val < 1000000) {
191             cyg_uint32 now = *PXA2X0_OSCR;
192             cyg_uint32 diff = now - prev;
193             val += NSECS_PER_TICK * diff;
194             prev = now;
195         }
196         val -= 1000000;
197     }
198 }
199
200
201 // Interrupt handling
202
203 // This routine is called to respond to a hardware interrupt (IRQ).  It
204 // should interrogate the hardware and return the IRQ vector number.
205 int hal_IRQ_handler(void)
206 {
207     cyg_uint32 sources, index;
208
209     sources = *PXA2X0_ICIP;
210
211 #ifdef HAL_EXTENDED_IRQ_HANDLER
212     // Use platform specific IRQ handler, if defined
213     // Note: this macro should do a 'return' with the appropriate
214     // interrupt number if such an extended interrupt exists.  The
215     // assumption is that the line after the macro starts 'normal' processing.
216     HAL_EXTENDED_IRQ_HANDLER(sources);
217 #endif
218
219     if ( sources & 0xff0000 )
220         index = 16;
221     else if ( sources & 0xff00 )
222         index = 8;
223     else if ( sources & 0xff )
224         index = 0;
225     else // if ( sources & 0xff000000 )
226         index = 24;
227
228     do {
229         if ( (1 << index) & sources ) {
230             if (index == CYGNUM_HAL_INTERRUPT_GPIOX) {
231                 // Special case of GPIO cascade.  Search for lowest set bit
232                 sources = *PXA2X0_GEDR0;
233                 index = 0;
234                 do {
235                     if (sources & (1 << index)) {
236                         return CYGNUM_HAL_INTERNAL_IRQS + index;
237                     }
238                     index++;
239                 } while (index < 32);
240                 sources = *PXA2X0_GEDR1;
241                 index = 0;
242                 do {
243                     if (sources & (1 << index)) {
244                         return CYGNUM_HAL_INTERNAL_IRQS + 32 + index;
245                     }
246                     index++;
247                 } while (index < 32);
248                 sources = *PXA2X0_GEDR2;
249                 index = 0;
250                 do {
251                     if (sources & (1 << index)) {
252                         return CYGNUM_HAL_INTERNAL_IRQS + 64 + index;
253                     }
254                     index++;
255                 } while (index < 32);
256 #ifdef CYGOPT_HAL_ARM_XSCALE_PXA2X0_VARIANT_PXA27X
257                 sources = *PXA2X0_GEDR3;
258                 index = 0;
259                 do {
260                     if (sources & (1 << index)) {
261                         return CYGNUM_HAL_INTERNAL_IRQS + 96 + index;
262                     }
263                     index++;
264                 } while (index < 32);
265 #endif
266             }
267             return index;
268         }
269       index++;
270     } while ( index & 7 );
271     
272     return CYGNUM_HAL_INTERRUPT_NONE; // This shouldn't happen!
273 }
274
275 void hal_interrupt_mask(int vector)
276 {
277
278 #ifdef HAL_EXTENDED_INTERRUPT_MASK
279     // Use platform specific handling, if defined
280     // Note: this macro should do a 'return' for "extended" values of 'vector'
281     // Normal vectors are handled by code subsequent to the macro call.
282     HAL_EXTENDED_INTERRUPT_MASK(vector);
283 #endif
284 #ifdef CYGOPT_HAL_ARM_XSCALE_PXA2X0_VARIANT_PXA27X
285     if (vector >= 32 && vector < CYGNUM_HAL_INTERNAL_IRQS) {
286         *PXA2X0_ICMR2 &= ~(1 << (vector - 32));
287         return;
288     }
289 #endif
290     if (vector >= CYGNUM_HAL_INTERRUPT_GPIO(2)) {
291         vector = CYGNUM_HAL_INTERRUPT_GPIOX;
292     }
293     *PXA2X0_ICMR &= ~(1 << vector);
294 }
295
296 void hal_interrupt_unmask(int vector)
297 {
298
299 #ifdef HAL_EXTENDED_INTERRUPT_UNMASK
300     // Use platform specific handling, if defined
301     // Note: this macro should do a 'return' for "extended" values of 'vector'
302     // Normal vectors are handled by code subsequent to the macro call.
303     HAL_EXTENDED_INTERRUPT_UNMASK(vector);
304 #endif
305 #ifdef CYGOPT_HAL_ARM_XSCALE_PXA2X0_VARIANT_PXA27X
306     if (vector >= 32 && vector < CYGNUM_HAL_INTERNAL_IRQS) {
307         *PXA2X0_ICMR2 |= (1 << (vector - 32));
308         return;
309     }
310 #endif
311     if (vector >= CYGNUM_HAL_INTERRUPT_GPIO(2)) {
312         vector = CYGNUM_HAL_INTERRUPT_GPIOX;
313     }
314     *PXA2X0_ICMR |= (1 << vector);
315 }
316
317 void hal_interrupt_acknowledge(int vector)
318 {
319
320 #ifdef HAL_EXTENDED_INTERRUPT_ACKNOWLEDGE
321     // Use platform specific handling, if defined
322     // Note: this macro should do a 'return' for "extended" values of 'vector'
323     // Normal vectors are handled by code subsequent to the macro call.
324     HAL_EXTENDED_INTERRUPT_ACKNOWLEDGE(vector);
325 #endif
326     if (vector == CYGNUM_HAL_INTERRUPT_GPIO0 || vector == CYGNUM_HAL_INTERRUPT_GPIO1) {
327         *PXA2X0_GEDR0  = (1 << (vector - 8));
328     } else {
329 #ifdef CYGOPT_HAL_ARM_XSCALE_PXA2X0_VARIANT_PXA27X
330         if (vector >= CYGNUM_HAL_INTERRUPT_GPIO(96)) {
331             *PXA2X0_GEDR3 = (1 << (vector - CYGNUM_HAL_INTERNAL_IRQS - 96));
332         } else
333 #endif
334         if (vector >= CYGNUM_HAL_INTERRUPT_GPIO(64)) {
335             *PXA2X0_GEDR2  = (1 << (vector - CYGNUM_HAL_INTERNAL_IRQS - 64));
336         } else if (vector >= CYGNUM_HAL_INTERRUPT_GPIO(32)) {
337             *PXA2X0_GEDR1  = (1 << (vector - CYGNUM_HAL_INTERNAL_IRQS - 32));
338         } else if (vector >= CYGNUM_HAL_INTERRUPT_GPIO(2)) {
339             *PXA2X0_GEDR0  = (1 << (vector - CYGNUM_HAL_INTERNAL_IRQS));
340         } else {
341             // Not a GPIO interrupt
342             return;
343         }
344     }
345 }
346
347 void hal_interrupt_configure(int vector, int level, int up)
348 {
349     cyg_bool falling = level || !up;
350     cyg_bool rising  = level || up;
351
352 #ifdef HAL_EXTENDED_INTERRUPT_CONFIGURE
353     // Use platform specific handling, if defined
354     // Note: this macro should do a 'return' for "extended" values of 'vector'
355     // Normal vectors are handled by code subsequent to the macro call.
356     HAL_EXTENDED_INTERRUPT_CONFIGURE(vector, level, up);
357 #endif
358 #ifdef CYGOPT_HAL_ARM_XSCALE_PXA2X0_VARIANT_PXA27X
359     if (vector >= CYGNUM_HAL_INTERRUPT_GPIO(96)) {
360         if (falling)
361             *PXA2X0_GFER3 |=  (1 << (vector - CYGNUM_HAL_INTERNAL_IRQS - 96));
362         else
363             *PXA2X0_GFER3 &= ~(1 << (vector - CYGNUM_HAL_INTERNAL_IRQS - 96));
364         if (rising)
365             *PXA2X0_GRER3 |=  (1 << (vector - CYGNUM_HAL_INTERNAL_IRQS - 96));
366         else
367             *PXA2X0_GRER3 &= ~(1 << (vector - CYGNUM_HAL_INTERNAL_IRQS - 96));
368     } else
369 #endif
370     if (vector >= CYGNUM_HAL_INTERRUPT_GPIO(64)) {
371         if (falling)
372             *PXA2X0_GFER2 |=  (1 << (vector - CYGNUM_HAL_INTERNAL_IRQS - 64));
373         else
374             *PXA2X0_GFER2 &= ~(1 << (vector - CYGNUM_HAL_INTERNAL_IRQS - 64));
375         if (rising)
376             *PXA2X0_GRER2 |=  (1 << (vector - CYGNUM_HAL_INTERNAL_IRQS - 64));
377         else
378             *PXA2X0_GRER2 &= ~(1 << (vector - CYGNUM_HAL_INTERNAL_IRQS - 64));
379     } else if (vector >= CYGNUM_HAL_INTERRUPT_GPIO(32)) {
380         if (falling)
381             *PXA2X0_GFER1 |=  (1 << (vector - CYGNUM_HAL_INTERNAL_IRQS - 32));
382         else
383             *PXA2X0_GFER1 &= ~(1 << (vector - CYGNUM_HAL_INTERNAL_IRQS - 32));
384         if (rising)
385             *PXA2X0_GRER1 |=  (1 << (vector - CYGNUM_HAL_INTERNAL_IRQS - 32));
386         else
387             *PXA2X0_GRER1 &= ~(1 << (vector - CYGNUM_HAL_INTERNAL_IRQS - 32));
388     } else if (vector >= CYGNUM_HAL_INTERRUPT_GPIO(2)) {
389         if (falling)
390             *PXA2X0_GFER1 |=  (1 << (vector - CYGNUM_HAL_INTERNAL_IRQS));
391         else
392             *PXA2X0_GFER1 &= ~(1 << (vector - CYGNUM_HAL_INTERNAL_IRQS));
393         if (rising)
394             *PXA2X0_GRER1 |=  (1 << (vector - CYGNUM_HAL_INTERNAL_IRQS));
395         else
396             *PXA2X0_GRER1 &= ~(1 << (vector - CYGNUM_HAL_INTERNAL_IRQS));
397     } else if (vector == CYGNUM_HAL_INTERRUPT_GPIO0 || vector == CYGNUM_HAL_INTERRUPT_GPIO1) {
398         if (falling)
399             *PXA2X0_GFER0 |=  (1 << (vector - 8));
400         else
401             *PXA2X0_GFER0 &= ~(1 << (vector - 8));
402         if (rising)
403             *PXA2X0_GRER0 |=  (1 << (vector - 8));
404         else
405             *PXA2X0_GRER0 &= ~(1 << (vector - 8));
406     }
407 }
408
409 void hal_interrupt_set_level(int vector, int level)
410 {
411
412 #ifdef HAL_EXTENDED_INTERRUPT_SET_LEVEL
413     // Use platform specific handling, if defined
414     // Note: this macro should do a 'return' for "extended" values of 'vector'
415     // Normal vectors are handled by code subsequent to the macro call.
416     HAL_EXTENDED_INTERRUPT_SET_LEVEL(vector, level);
417 #endif
418 }
419