]> git.kernelconcepts.de Git - karo-tx-redboot.git/blob - packages/hal/arm/xscale/pxa2x0/v2_0/src/pxa2x0_misc.c
Initial revision
[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     *PXA2X0_GEDR0 = 0xffffffff; // Clear edge detect status
89     *PXA2X0_GEDR1 = 0xffffffff;
90     *PXA2X0_GEDR2 = 0x0001ffff;
91
92     plf_hardware_init();        // Perform any platform specific initializations
93
94     *PXA2X0_OSCR = 0;           // Let the "OS" counter run
95     *PXA2X0_OSMR0 = 0;
96
97 #ifdef CYGSEM_HAL_ENABLE_DCACHE_ON_STARTUP
98     HAL_DCACHE_ENABLE();        // Enable caches
99 #endif
100 #ifdef CYGSEM_HAL_ENABLE_ICACHE_ON_STARTUP
101     HAL_ICACHE_ENABLE();
102 #endif
103 }
104
105 //
106 // GPIO support functions
107 //
108 void
109 _pxa2x0_set_GPIO_mode(int bit, int mode, int dir)
110 {
111     int bank = bit / 32;
112     unsigned volatile long *gpdr, *gafr;
113
114     gpdr = &PXA2X0_GPDR0[bank];
115     gafr = &PXA2X0_GAFR0_L[(bit&0x30)>>4];
116     bit %= 32;
117     // Data direction registers have 1 bit per GPIO
118     *gpdr = (*gpdr & ~(1<<bit)) | (dir<<bit);
119     // Alternate function regusters have 2 bits per GPIO
120     bit = (bit & 0x0F) * 2;
121     *gafr = (*gafr & ~(3<<bit)) | (mode<<bit);
122 }
123
124
125 // Initialize the clock
126 static cyg_uint32  clock_period;
127
128 void hal_clock_initialize(cyg_uint32 period)
129 {
130         *PXA2X0_OSMR0 = period;                                 // Load match value
131         clock_period = period;
132     
133         *PXA2X0_OSCR = 0;                                               // Start the counter
134     *PXA2X0_OSSR = PXA2X0_OSSR_TIMER0;          // Clear any pending interrupt
135     *PXA2X0_OIER |= PXA2X0_OIER_TIMER0;         // Enable timer 0 interrupt
136
137     HAL_INTERRUPT_UNMASK( CYGNUM_HAL_INTERRUPT_TIMER0 );        // Unmask timer 0 interrupt
138 }
139
140 // This routine is called during a clock interrupt.
141 void hal_clock_reset(cyg_uint32 vector, cyg_uint32 period)
142 {
143     *PXA2X0_OSMR0 = *PXA2X0_OSCR + period;      // Load new match value
144     *PXA2X0_OSSR = PXA2X0_OSSR_TIMER0;          // Clear any pending interrupt
145 }
146
147 // Read the current value of the clock, returning the number of hardware
148 // "ticks" that have occurred (i.e. how far away the current value is from
149 // the start)
150
151 // Note: The "contract" for this function is that the value is the number
152 // of hardware clocks that have happened since the last interrupt (i.e.
153 // when it was reset).  This value is used to measure interrupt latencies.
154 // However, since the hardware counter runs freely, this routine computes
155 // the difference between the current clock period and the number of hardware
156 // ticks left before the next timer interrupt.
157 void hal_clock_read(cyg_uint32 *pvalue)
158 {
159     int orig;
160     HAL_DISABLE_INTERRUPTS(orig);
161     *pvalue = clock_period + *PXA2X0_OSCR - *PXA2X0_OSMR0;
162     HAL_RESTORE_INTERRUPTS(orig);
163 }
164
165 // Delay for some number of micro-seconds
166 void hal_delay_us(cyg_int32 usecs)
167 {
168     cyg_uint32 val = 0;
169     cyg_uint32 ctr = *PXA2X0_OSCR;
170     while (usecs-- > 0) {
171         do {
172             if (ctr != *PXA2X0_OSCR) {
173                 val += 271267;          // 271267ps (3.6865Mhz -> 271.267ns)
174                 ++ctr;
175             }
176         } while (val < 1000000);
177         val -= 1000000;
178     }
179 }
180
181
182 // Interrupt handling
183
184 // This routine is called to respond to a hardware interrupt (IRQ).  It
185 // should interrogate the hardware and return the IRQ vector number.
186 int hal_IRQ_handler(void)
187 {
188     cyg_uint32 sources, index;
189
190     sources = *PXA2X0_ICIP;
191
192 #ifdef HAL_EXTENDED_IRQ_HANDLER
193     // Use platform specific IRQ handler, if defined
194     // Note: this macro should do a 'return' with the appropriate
195     // interrupt number if such an extended interrupt exists.  The
196     // assumption is that the line after the macro starts 'normal' processing.
197     HAL_EXTENDED_IRQ_HANDLER(sources);
198 #endif
199
200     if ( sources & 0xff0000 )
201         index = 16;
202     else if ( sources & 0xff00 )
203         index = 8;
204     else if ( sources & 0xff )
205         index = 0;
206     else // if ( sources & 0xff000000 )
207         index = 24;
208
209     do {
210         if ( (1 << index) & sources ) {
211             if (index == CYGNUM_HAL_INTERRUPT_GPIO) {
212                 // Special case of GPIO cascade.  Search for lowest set bit
213                 sources = *PXA2X0_GEDR0;
214                 index = 0;
215                 do {
216                     if (sources & (1 << index)) {
217                         return index+32;
218                     }
219                     index++;
220                 } while (index < 32);
221                 sources = *PXA2X0_GEDR1;
222                 index = 0;
223                 do {
224                     if (sources & (1 << index)) {
225                         return index+64;
226                     }
227                     index++;
228                 } while (index < 32);
229                 sources = *PXA2X0_GEDR2;
230                 index = 0;
231                 do {
232                     if (sources & (1 << index)) {
233                         return index+96;
234                     }
235                     index++;
236                 } while (index < 21);
237
238             }
239             return index;
240         }
241       index++;
242     } while ( index & 7 );
243     
244     return CYGNUM_HAL_INTERRUPT_NONE; // This shouldn't happen!
245 }
246
247 void hal_interrupt_mask(int vector)
248 {
249
250 #ifdef HAL_EXTENDED_INTERRUPT_MASK
251     // Use platform specific handling, if defined
252     // Note: this macro should do a 'return' for "extended" values of 'vector'
253     // Normal vectors are handled by code subsequent to the macro call.
254     HAL_EXTENDED_INTERRUPT_MASK(vector);
255 #endif
256     
257     if (vector >= CYGNUM_HAL_INTERRUPT_GPIO2) {
258         vector = CYGNUM_HAL_INTERRUPT_GPIO;
259     }
260     *PXA2X0_ICMR &= ~(1 << vector);
261 }
262
263 void hal_interrupt_unmask(int vector)
264 {
265
266 #ifdef HAL_EXTENDED_INTERRUPT_UNMASK
267     // Use platform specific handling, if defined
268     // Note: this macro should do a 'return' for "extended" values of 'vector'
269     // Normal vectors are handled by code subsequent to the macro call.
270     HAL_EXTENDED_INTERRUPT_UNMASK(vector);
271 #endif
272
273     if (vector >= CYGNUM_HAL_INTERRUPT_GPIO2) {
274         vector = CYGNUM_HAL_INTERRUPT_GPIO;
275     }
276     *PXA2X0_ICMR |= (1 << vector);
277 }
278
279 void hal_interrupt_acknowledge(int vector)
280 {
281
282 #ifdef HAL_EXTENDED_INTERRUPT_ACKNOWLEDGE
283     // Use platform specific handling, if defined
284     // Note: this macro should do a 'return' for "extended" values of 'vector'
285     // Normal vectors are handled by code subsequent to the macro call.
286     HAL_EXTENDED_INTERRUPT_ACKNOWLEDGE(vector);
287 #endif
288         if (vector == CYGNUM_HAL_INTERRUPT_GPIO0 || vector == CYGNUM_HAL_INTERRUPT_GPIO1)
289         {
290                 *PXA2X0_GEDR0  = (1 << (vector - 8));
291         }else{
292             if (vector >= CYGNUM_HAL_INTERRUPT_GPIO64) {
293                         *PXA2X0_GEDR2  = (1 << (vector - 96));
294                 } else if (vector >= CYGNUM_HAL_INTERRUPT_GPIO32) {
295                         *PXA2X0_GEDR1  = (1 << (vector - 64));
296                 } else if (vector >= CYGNUM_HAL_INTERRUPT_GPIO2) {
297                         *PXA2X0_GEDR0  = (1 << (vector - 32));
298                 } else {
299                         // Not a GPIO interrupt
300                         return;
301                 }
302         }
303 }
304
305 void hal_interrupt_configure(int vector, int level, int up)
306 {
307
308 #ifdef HAL_EXTENDED_INTERRUPT_CONFIGURE
309     // Use platform specific handling, if defined
310     // Note: this macro should do a 'return' for "extended" values of 'vector'
311     // Normal vectors are handled by code subsequent to the macro call.
312     HAL_EXTENDED_INTERRUPT_CONFIGURE(vector, level, up);
313 #endif
314     if (vector >= CYGNUM_HAL_INTERRUPT_GPIO64) {
315         if (level) {
316             if (up) {
317                 // Enable both edges
318                 *PXA2X0_GRER2 |= (1 << (vector - 96));
319                 *PXA2X0_GFER2 |= (1 << (vector - 96));
320             } else {
321                 // Disable both edges
322                 *PXA2X0_GRER2 &= ~(1 << (vector - 96));
323                 *PXA2X0_GFER2 &= ~(1 << (vector - 96));
324             }
325         } else {
326             // Only interested in one edge
327             if (up) {
328                 // Set rising edge detect and clear falling edge detect.
329                 *PXA2X0_GRER2 |= (1 << (vector - 96));
330                 *PXA2X0_GFER2 &= ~(1 << (vector - 96));
331             } else {
332                 // Set falling edge detect and clear rising edge detect.
333                 *PXA2X0_GFER2 |= (1 << (vector - 96));
334                 *PXA2X0_GRER2 &= ~(1 << (vector - 96));
335             }
336         }
337     } else if (vector >= CYGNUM_HAL_INTERRUPT_GPIO32) {
338         if (level) {
339             if (up) {
340                 // Enable both edges
341                 *PXA2X0_GRER1 |= (1 << (vector - 64));
342                 *PXA2X0_GFER1 |= (1 << (vector - 64));
343             } else {
344                 // Disable both edges
345                 *PXA2X0_GRER1 &= ~(1 << (vector - 64));
346                 *PXA2X0_GFER1 &= ~(1 << (vector - 64));
347             }
348         } else {
349             // Only interested in one edge
350             if (up) {
351                 // Set rising edge detect and clear falling edge detect.
352                 *PXA2X0_GRER1 |= (1 << (vector - 64));
353                 *PXA2X0_GFER1 &= ~(1 << (vector - 64));
354             } else {
355                 // Set falling edge detect and clear rising edge detect.
356                 *PXA2X0_GFER1 |= (1 << (vector - 64));
357                 *PXA2X0_GRER1 &= ~(1 << (vector - 64));
358             }
359         }
360     } else if (vector >= CYGNUM_HAL_INTERRUPT_GPIO2) {
361         if (level) {
362             if (up) {
363                 // Enable both edges
364                 *PXA2X0_GRER0 |= (1 << (vector - 32));
365                 *PXA2X0_GFER0 |= (1 << (vector - 32));
366             } else {
367                 // Disable both edges
368                 *PXA2X0_GRER0 &= ~(1 << (vector - 32));
369                 *PXA2X0_GFER0 &= ~(1 << (vector - 32));
370             }
371         } else {
372             // Only interested in one edge
373             if (up) {
374                 // Set rising edge detect and clear falling edge detect.
375                 *PXA2X0_GRER0 |= (1 << (vector - 32));
376                 *PXA2X0_GFER0 &= ~(1 << (vector - 32));
377             } else {
378                 // Set falling edge detect and clear rising edge detect.
379                 *PXA2X0_GFER0 |= (1 << (vector - 32));
380                 *PXA2X0_GRER0 &= ~(1 << (vector - 32));
381             }
382         }
383     } else if (vector == CYGNUM_HAL_INTERRUPT_GPIO0 || vector == CYGNUM_HAL_INTERRUPT_GPIO1)
384         {
385         if (level) {
386             if (up) {
387                 // Enable both edges
388                 *PXA2X0_GRER0 |= (1 << (vector - 8));
389                 *PXA2X0_GFER0 |= (1 << (vector - 8));
390             } else {
391                 // Disable both edges
392                 *PXA2X0_GRER0 &= ~(1 << (vector - 8));
393                 *PXA2X0_GFER0 &= ~(1 << (vector - 8));
394             }
395         } else {
396             // Only interested in one edge
397             if (up) {
398                 // Set rising edge detect and clear falling edge detect.
399                 *PXA2X0_GRER0 |= (1 << (vector - 8));
400                 *PXA2X0_GFER0 &= ~(1 << (vector - 8));
401             } else {
402                 // Set falling edge detect and clear rising edge detect.
403                 *PXA2X0_GFER0 |= (1 << (vector - 8));
404                 *PXA2X0_GRER0 &= ~(1 << (vector - 8));
405             }
406         }
407         }
408
409
410 }
411
412 void hal_interrupt_set_level(int vector, int level)
413 {
414
415 #ifdef HAL_EXTENDED_INTERRUPT_SET_LEVEL
416     // Use platform specific handling, if defined
417     // Note: this macro should do a 'return' for "extended" values of 'vector'
418     // Normal vectors are handled by code subsequent to the macro call.
419     HAL_EXTENDED_INTERRUPT_SET_LEVEL(vector, level);
420 #endif
421 }
422