]> git.karo-electronics.de Git - karo-tx-redboot.git/blob - packages/hal/arm/xscale/verde/v2_0/src/verde_misc.c
Initial revision
[karo-tx-redboot.git] / packages / hal / arm / xscale / verde / v2_0 / src / verde_misc.c
1 //==========================================================================
2 //
3 //      verde_misc.c
4 //
5 //      HAL misc board support code for Intel Verde I/O Coprocessor
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, 2003 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 //#####DESCRIPTIONBEGIN####
42 //
43 // Author(s):    msalter
44 // Contributors: msalter
45 // Date:         2001-12-03
46 // Purpose:      HAL board support
47 // Description:  Implementations of HAL board interfaces
48 //
49 //####DESCRIPTIONEND####
50 //
51 //========================================================================*/
52
53 #include <pkgconf/hal.h>
54 #include <pkgconf/system.h>
55 #include CYGBLD_HAL_PLATFORM_H
56 #include CYGHWR_MEMORY_LAYOUT_H
57
58 #include <cyg/infra/cyg_type.h>         // base types
59 #include <cyg/infra/cyg_trac.h>         // tracing macros
60 #include <cyg/infra/cyg_ass.h>          // assertion macros
61
62 #include <cyg/hal/hal_io.h>             // IO macros
63 #include <cyg/hal/hal_stub.h>           // Stub macros
64 #include <cyg/hal/hal_if.h>             // calling interface API
65 #include <cyg/hal/hal_arch.h>           // Register state info
66 #include <cyg/hal/hal_diag.h>
67 #include <cyg/hal/hal_intr.h>           // Interrupt names
68 #include <cyg/hal/hal_cache.h>
69 #include <cyg/hal/plf_io.h>
70 #include <cyg/infra/diag.h>             // diag_printf
71 #include <cyg/hal/drv_api.h>            // CYG_ISR_HANDLED
72
73 // Most initialization has already been done before we get here.
74 // All we do here is set up the interrupt environment.
75 // FIXME: some of the stuff in hal_platform_setup could be moved here.
76
77 externC void plf_hardware_init(void);
78
79 static cyg_uint32 mcu_ISR(cyg_vector_t vector, cyg_addrword_t data);
80
81 void
82 hal_hardware_init(void)
83 {
84     hal_xscale_core_init();
85
86     // Perform any platform specific initializations
87     plf_hardware_init();
88
89     // Let the timer run at a default rate (for delays)
90     hal_clock_initialize(CYGNUM_HAL_RTC_PERIOD);
91
92     // Set up eCos/ROM interfaces
93     hal_if_init();
94
95     // Enable caches
96     HAL_DCACHE_ENABLE();
97     HAL_ICACHE_ENABLE();
98
99     // attach interrupt handlers for MCU errors
100     HAL_INTERRUPT_ATTACH (CYGNUM_HAL_INTERRUPT_MCU_ERR, &mcu_ISR, CYGNUM_HAL_INTERRUPT_MCU_ERR, 0);
101     HAL_INTERRUPT_UNMASK (CYGNUM_HAL_INTERRUPT_MCU_ERR);
102 }
103
104 // -------------------------------------------------------------------------
105 // This routine is called to respond to a hardware interrupt (IRQ).  It
106 // should interrogate the hardware and return the IRQ vector number.
107
108 int
109 hal_IRQ_handler(void)
110 {
111     cyg_uint32 sources, mask;
112     int index;
113
114     INTCTL_READ(mask);
115     IINTSRC_READ(sources);
116
117     sources &= mask; // just the unmasked ones
118
119     if (sources) {
120         HAL_LSBIT_INDEX( index, sources );
121         return index;
122     }
123     return CYGNUM_HAL_INTERRUPT_NONE; // This shouldn't happen!
124 }
125
126 static inline void
127 _scrub_ecc(unsigned p)
128 {
129     cyg_uint32 iacr;
130
131     // The following ldr/str pair need to be atomic on the bus. Since
132     // the XScale core doesn't support atomic RMW, we have to disable
133     // arbitration to prevent other bus masters from taking the bus
134     // between the the ldr and str.
135
136     // Disable internal bus arbitration for everything except the CPU
137     iacr = *ARB_IACR;
138     *ARB_IACR = IACR_ATU(IACR_PRI_OFF)  | IACR_DMA0(IACR_PRI_OFF) |
139                 IACR_DMA1(IACR_PRI_OFF) | IACR_AAU(IACR_PRI_OFF)  |
140                 IACR_PBI(IACR_PRI_OFF)  | IACR_CORE(IACR_PRI_HIGH);
141
142     // drain write buffer
143     asm volatile ("mcr  p15,0,r1,c7,c10,4\n");
144     CPWAIT();
145
146     asm volatile ("ldrb r4, [%0]\n"
147                   "strb r4, [%0]\n" : : "r"(p) : "r4");
148
149     // Restore normal internal bus arbitration priorities
150     *ARB_IACR = iacr;
151 }
152
153 static cyg_uint32
154 mcu_ISR(cyg_vector_t vector, cyg_addrword_t data)
155 {
156     cyg_uint32 eccr_reg, mcisr_reg;
157
158     // Read current state of ECC register
159     eccr_reg = *MCU_ECCR;
160
161     // and the interrupt status
162     mcisr_reg = *MCU_MCISR;
163
164     // Turn off all ecc error reporting
165     *MCU_ECCR = 0xc;
166
167 #ifdef DEBUG_ECC
168     diag_printf("mcu_ISR entry: ECCR = 0x%X, MCISR = 0x%X\n", eccr_reg, mcisr_reg);
169 #endif
170
171     // Check for ECC Error 0
172     if(mcisr_reg & 1) {
173         
174 #ifdef DEBUG_ECC
175         diag_printf("ELOG0 = 0x%X\n", *MCU_ELOG0);
176         diag_printf("ECC Error Detected at Address 0x%X\n",*MCU_ECAR0);
177 #endif
178         
179         // Check for single-bit error
180         if(!(*MCU_ELOG0 & 0x00000100)) {
181             // call ECC restoration function
182             _scrub_ecc((*MCU_ECAR0 - SDRAM_PHYS_BASE) + SDRAM_UNCACHED_BASE);
183
184             // Clear the MCISR
185             *MCU_MCISR = 1;
186         } else {
187 #ifdef DEBUG_ECC
188             diag_printf("Multi-bit or nibble error\n");
189 #endif
190         }
191     }
192
193     // Check for ECC Error 1
194     if(mcisr_reg & 2) {
195
196 #ifdef DEBUG_ECC
197         diag_printf("ELOG1 = 0x%X\n",*MCU_ELOG1);
198         diag_printf("ECC Error Detected at Address 0x%X\n",*MCU_ECAR1); 
199 #endif
200         
201         // Check for single-bit error
202         if(!(*MCU_ELOG1 & 0x00000100))  {
203             // call ECC restoration function
204             _scrub_ecc((*MCU_ECAR1 - SDRAM_PHYS_BASE) + SDRAM_UNCACHED_BASE);
205  
206             // Clear the MCISR
207             *MCU_MCISR = 2;
208         }
209         else {
210 #ifdef DEBUG_ECC
211             diag_printf("Multi-bit or nibble error\n");
212 #endif
213         }
214     }
215
216     // Check for ECC Error N
217     if(mcisr_reg & 4) {
218         // Clear the MCISR
219         *MCU_MCISR = 4;
220         diag_printf("Uncorrectable error during RMW\n");
221     }
222     
223     // Restore ECCR register
224     *MCU_ECCR = eccr_reg;
225
226 #ifdef DEBUG_ECC
227     diag_printf("mcu_ISR exit: MCISR = 0x%X\n", *MCU_MCISR);
228 #endif
229
230     return CYG_ISR_HANDLED;
231 }
232
233 //
234 // Interrupt control
235 //
236
237 void
238 hal_interrupt_mask(int vector)
239 {
240     if (vector <= CYGNUM_HAL_INTERRUPT_HPI) {
241         int mask;
242
243         INTCTL_READ(mask);
244         mask &= ~(1 << vector);
245         INTCTL_WRITE(mask);
246         CPWAIT();
247     }
248 }
249
250 void
251 hal_interrupt_unmask(int vector)
252 {
253     if (vector <= CYGNUM_HAL_INTERRUPT_HPI) {
254         int mask;
255
256         INTCTL_READ(mask);
257         mask |= (1 << vector);
258         INTCTL_WRITE(mask);
259         CPWAIT();
260     }
261 }
262
263 void
264 hal_interrupt_acknowledge(int vector)
265 {
266     // If this is a timer interrupt, write a 1 to the appropriate bit
267     // in the TISR register.
268     if( vector == CYGNUM_HAL_INTERRUPT_TIMER0 ||
269         vector == CYGNUM_HAL_INTERRUPT_TIMER1 )
270     {
271         TISR_WRITE(1<<(vector-CYGNUM_HAL_INTERRUPT_TIMER0));
272     }
273 }
274
275
276 void hal_interrupt_configure(int vector, int level, int up)
277 {
278 }
279
280 void hal_interrupt_set_level(int vector, int level)
281 {
282 }
283
284
285 /*------------------------------------------------------------------------*/
286 // RTC Support
287
288 static cyg_uint32 _period;
289
290 #define CLOCK_MULTIPLIER 200
291
292 void
293 hal_clock_initialize(cyg_uint32 period)
294 {
295     cyg_uint32 val;
296     cyg_uint32 tmr_period;
297     _period = period;
298
299     tmr_period = period * CLOCK_MULTIPLIER;
300     
301     // disable timer
302     TMR0_WRITE(0);
303
304     // clear interrupts
305     TISR_WRITE(1);
306
307     // set reload/count value
308     TRR0_WRITE(tmr_period);
309     TCR0_WRITE(tmr_period);
310
311     // let it run
312     TMR0_WRITE(TMR_ENABLE | TMR_RELOAD | TMR_CLK_1);
313
314     TMR0_READ(val);
315 }
316
317
318 // Dynamically set the timer interrupt rate.
319 // Not for eCos application use at all, just special GPROF code in RedBoot.
320
321 void
322 hal_clock_reinitialize(          int *pfreq,    /* inout */
323                         unsigned int *pperiod,  /* inout */
324                         unsigned int old_hz )   /* in */
325 {
326     unsigned int newp = 0, period, i = 0;
327     int hz;
328     int do_set_hw;
329
330 // Arbitrary choice somewhat - so the CPU can make
331 // progress with the clock set like this, we hope.
332 #define MIN_TICKS (2000)
333 #define MAX_TICKS  N/A: 32-bit counter
334
335     if ( ! pfreq || ! pperiod )
336         return; // we cannot even report a problem!
337
338     hz = *pfreq;
339     period = *pperiod;
340
341 // Requested HZ:
342 // 0         => tell me the current value (no change, implemented in caller)
343 // - 1       => tell me the slowest (no change)
344 // - 2       => tell me the default (no change, implemented in caller)
345 // -nnn      => tell me what you would choose for nnn (no change)
346 // MIN_INT   => tell me the fastest (no change)
347 //        
348 // 1         => tell me the slowest (sets the clock)
349 // MAX_INT   => tell me the fastest (sets the clock)
350
351     do_set_hw = (hz > 0);
352     if ( hz < 0 )
353         hz = -hz;
354
355     // Be paranoid about bad args, and very defensive about underflows
356     if ( 0 < hz && 0 < period && 0 < old_hz ) {
357
358         newp = period * old_hz / (unsigned)hz;
359
360         if ( newp < MIN_TICKS ) {
361             newp = MIN_TICKS;
362             // recalculate to get the exact delay for this integral hz
363             // and hunt hz down to an acceptable value if necessary
364             i = period * old_hz / newp;
365             if ( i ) do {
366                 newp = period * old_hz / i;
367                 i--;
368             } while (newp < MIN_TICKS && i);
369         }
370         // So long as period * old_hz fits in 32 bits, there is no need to
371         // worry about overflow; hz >= 1 in the initial divide.  If the
372         // clock cannot do a whole second (period * old_hz >= 2^32), we
373         // will get overflow here, and random returned HZ values.
374
375         // Recalculate the actual value installed.
376         i = period * old_hz / newp;
377     }
378
379     *pfreq = i;
380     *pperiod = newp;
381
382     if ( do_set_hw ) {
383         hal_clock_initialize( newp );
384     }
385 }
386
387 // This routine is called during a clock interrupt.
388 void
389 hal_clock_reset(cyg_uint32 vector, cyg_uint32 period)
390 {
391 }
392
393 // Read the current value of the clock, returning the number of hardware
394 // "ticks" that have occurred (i.e. how far away the current value is from
395 // the start)
396 void
397 hal_clock_read(cyg_uint32 *pvalue)
398 {
399     cyg_uint32 timer_val;
400
401     TCR0_READ(timer_val);
402
403     // Translate timer value back into microseconds
404     
405     timer_val /= CLOCK_MULTIPLIER;
406     
407     *pvalue = _period - timer_val;
408 }
409
410 // Delay for some usecs.
411 void
412 hal_delay_us(cyg_int32 delay)
413 {
414 #define _TICKS_PER_USEC CLOCK_MULTIPLIER
415     cyg_uint32 now, prev, diff, usecs;
416     cyg_uint32 tmr_period = _period * CLOCK_MULTIPLIER;
417
418     diff = usecs = 0;
419     TCR0_READ(prev);
420
421     while (delay > usecs) {
422         TCR0_READ(now);
423
424         if (prev < now)
425             diff += (prev + (tmr_period - now));
426         else
427             diff += (prev - now);
428
429         prev = now;
430
431         if (diff >= _TICKS_PER_USEC) {
432             usecs += (diff / _TICKS_PER_USEC);
433             diff %= _TICKS_PER_USEC;
434         }
435     }
436 }
437
438 /*------------------------------------------------------------------------*/
439 // EOF verde_misc.c
440