1 //==========================================================================
5 // HAL misc board support code for Intel Verde I/O Coprocessor
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.
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.
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
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.
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.
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.
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####
44 // Contributors: msalter
46 // Purpose: HAL board support
47 // Description: Implementations of HAL board interfaces
49 //####DESCRIPTIONEND####
51 //========================================================================*/
53 #include <pkgconf/hal.h>
54 #include <pkgconf/system.h>
55 #include CYGBLD_HAL_PLATFORM_H
56 #include CYGHWR_MEMORY_LAYOUT_H
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
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
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.
77 externC void plf_hardware_init(void);
79 static cyg_uint32 mcu_ISR(cyg_vector_t vector, cyg_addrword_t data);
82 hal_hardware_init(void)
84 hal_xscale_core_init();
86 // Perform any platform specific initializations
89 // Let the timer run at a default rate (for delays)
90 hal_clock_initialize(CYGNUM_HAL_RTC_PERIOD);
92 // Set up eCos/ROM interfaces
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);
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.
109 hal_IRQ_handler(void)
111 cyg_uint32 sources, mask;
115 IINTSRC_READ(sources);
117 sources &= mask; // just the unmasked ones
120 HAL_LSBIT_INDEX( index, sources );
123 return CYGNUM_HAL_INTERRUPT_NONE; // This shouldn't happen!
127 _scrub_ecc(unsigned p)
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.
136 // Disable internal bus arbitration for everything except the CPU
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);
142 // drain write buffer
143 asm volatile ("mcr p15,0,r1,c7,c10,4\n");
146 asm volatile ("ldrb r4, [%0]\n"
147 "strb r4, [%0]\n" : : "r"(p) : "r4");
149 // Restore normal internal bus arbitration priorities
154 mcu_ISR(cyg_vector_t vector, cyg_addrword_t data)
156 cyg_uint32 eccr_reg, mcisr_reg;
158 // Read current state of ECC register
159 eccr_reg = *MCU_ECCR;
161 // and the interrupt status
162 mcisr_reg = *MCU_MCISR;
164 // Turn off all ecc error reporting
168 diag_printf("mcu_ISR entry: ECCR = 0x%X, MCISR = 0x%X\n", eccr_reg, mcisr_reg);
171 // Check for ECC Error 0
175 diag_printf("ELOG0 = 0x%X\n", *MCU_ELOG0);
176 diag_printf("ECC Error Detected at Address 0x%X\n",*MCU_ECAR0);
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);
188 diag_printf("Multi-bit or nibble error\n");
193 // Check for ECC Error 1
197 diag_printf("ELOG1 = 0x%X\n",*MCU_ELOG1);
198 diag_printf("ECC Error Detected at Address 0x%X\n",*MCU_ECAR1);
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);
211 diag_printf("Multi-bit or nibble error\n");
216 // Check for ECC Error N
220 diag_printf("Uncorrectable error during RMW\n");
223 // Restore ECCR register
224 *MCU_ECCR = eccr_reg;
227 diag_printf("mcu_ISR exit: MCISR = 0x%X\n", *MCU_MCISR);
230 return CYG_ISR_HANDLED;
238 hal_interrupt_mask(int vector)
240 if (vector <= CYGNUM_HAL_INTERRUPT_HPI) {
244 mask &= ~(1 << vector);
251 hal_interrupt_unmask(int vector)
253 if (vector <= CYGNUM_HAL_INTERRUPT_HPI) {
257 mask |= (1 << vector);
264 hal_interrupt_acknowledge(int vector)
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 )
271 TISR_WRITE(1<<(vector-CYGNUM_HAL_INTERRUPT_TIMER0));
276 void hal_interrupt_configure(int vector, int level, int up)
280 void hal_interrupt_set_level(int vector, int level)
285 /*------------------------------------------------------------------------*/
288 static cyg_uint32 _period;
290 #define CLOCK_MULTIPLIER 200
293 hal_clock_initialize(cyg_uint32 period)
296 cyg_uint32 tmr_period;
299 tmr_period = period * CLOCK_MULTIPLIER;
307 // set reload/count value
308 TRR0_WRITE(tmr_period);
309 TCR0_WRITE(tmr_period);
312 TMR0_WRITE(TMR_ENABLE | TMR_RELOAD | TMR_CLK_1);
318 // Dynamically set the timer interrupt rate.
319 // Not for eCos application use at all, just special GPROF code in RedBoot.
322 hal_clock_reinitialize( int *pfreq, /* inout */
323 unsigned int *pperiod, /* inout */
324 unsigned int old_hz ) /* in */
326 unsigned int newp = 0, period, i = 0;
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
335 if ( ! pfreq || ! pperiod )
336 return; // we cannot even report a problem!
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)
348 // 1 => tell me the slowest (sets the clock)
349 // MAX_INT => tell me the fastest (sets the clock)
351 do_set_hw = (hz > 0);
355 // Be paranoid about bad args, and very defensive about underflows
356 if ( 0 < hz && 0 < period && 0 < old_hz ) {
358 newp = period * old_hz / (unsigned)hz;
360 if ( 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;
366 newp = period * old_hz / i;
368 } while (newp < MIN_TICKS && i);
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.
375 // Recalculate the actual value installed.
376 i = period * old_hz / newp;
383 hal_clock_initialize( newp );
387 // This routine is called during a clock interrupt.
389 hal_clock_reset(cyg_uint32 vector, cyg_uint32 period)
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
397 hal_clock_read(cyg_uint32 *pvalue)
399 cyg_uint32 timer_val;
401 TCR0_READ(timer_val);
403 // Translate timer value back into microseconds
405 timer_val /= CLOCK_MULTIPLIER;
407 *pvalue = _period - timer_val;
410 // Delay for some usecs.
412 hal_delay_us(cyg_int32 delay)
414 #define _TICKS_PER_USEC CLOCK_MULTIPLIER
415 cyg_uint32 now, prev, diff, usecs;
416 cyg_uint32 tmr_period = _period * CLOCK_MULTIPLIER;
421 while (delay > usecs) {
425 diff += (prev + (tmr_period - now));
427 diff += (prev - now);
431 if (diff >= _TICKS_PER_USEC) {
432 usecs += (diff / _TICKS_PER_USEC);
433 diff %= _TICKS_PER_USEC;
438 /*------------------------------------------------------------------------*/