diff options
Diffstat (limited to 'cpu/ixp/interrupts.c')
-rw-r--r-- | cpu/ixp/interrupts.c | 115 |
1 files changed, 103 insertions, 12 deletions
diff --git a/cpu/ixp/interrupts.c b/cpu/ixp/interrupts.c index e260dea..2dd9561 100644 --- a/cpu/ixp/interrupts.c +++ b/cpu/ixp/interrupts.c @@ -1,5 +1,7 @@ -/* vi: set ts=8 sw=8 noet: */ /* + * (C) Copyright 2006 + * Stefan Roese, DENX Software Engineering, sr@denx.de. + * * (C) Copyright 2002 * Sysgo Real-Time Solutions, GmbH <www.elinos.com> * Marius Groeger <mgroeger@sysgo.de> @@ -31,22 +33,85 @@ #include <asm/arch/ixp425.h> #ifdef CONFIG_USE_IRQ +/* + * When interrupts are enabled, use timer 2 for time/delay generation... + */ + +#define FREQ 66666666 +#define CLOCK_TICK_RATE (((FREQ / CFG_HZ & ~IXP425_OST_RELOAD_MASK) + 1) * CFG_HZ) +#define LATCH ((CLOCK_TICK_RATE + CFG_HZ/2) / CFG_HZ) /* For divider */ + +struct _irq_handler { + void *m_data; + void (*m_func)( void *data); +}; + +static struct _irq_handler IRQ_HANDLER[N_IRQS]; + +static volatile ulong timestamp; + /* enable IRQ/FIQ interrupts */ -void enable_interrupts (void) +void enable_interrupts(void) { -#error: interrupts not implemented yet + unsigned long temp; + __asm__ __volatile__("mrs %0, cpsr\n" + "bic %0, %0, #0x80\n" + "msr cpsr_c, %0" + : "=r" (temp) + : + : "memory"); } - /* * disable IRQ/FIQ interrupts * returns true if interrupts had been enabled before we disabled them */ -int disable_interrupts (void) +int disable_interrupts(void) { -#error: interrupts not implemented yet + unsigned long old,temp; + __asm__ __volatile__("mrs %0, cpsr\n" + "orr %1, %0, #0x80\n" + "msr cpsr_c, %1" + : "=r" (old), "=r" (temp) + : + : "memory"); + return (old & 0x80) == 0; } -#else + +static void default_isr(void *data) +{ + printf("default_isr(): called for IRQ %d, Interrupt Status=%x PR=%x\n", + (int)data, *IXP425_ICIP, *IXP425_ICIH); +} + +static int next_irq(void) +{ + return (((*IXP425_ICIH & 0x000000fc) >> 2) - 1); +} + +static void timer_isr(void *data) +{ + unsigned int *pTime = (unsigned int *)data; + + (*pTime)++; + + /* + * Reset IRQ source + */ + *IXP425_OSST = IXP425_OSST_TIMER_2_PEND; +} + +ulong get_timer (ulong base) +{ + return timestamp - base; +} + +void reset_timer (void) +{ + timestamp = 0; +} + +#else /* #ifdef CONFIG_USE_IRQ */ void enable_interrupts (void) { return; @@ -55,8 +120,7 @@ int disable_interrupts (void) { return 0; } -#endif - +#endif /* #ifdef CONFIG_USE_IRQ */ void bad_mode (void) { @@ -140,19 +204,46 @@ void do_fiq (struct pt_regs *pt_regs) { printf ("fast interrupt request\n"); show_regs (pt_regs); - bad_mode (); + printf("IRQ=%08lx FIQ=%08lx\n", *IXP425_ICIH, *IXP425_ICFH); } void do_irq (struct pt_regs *pt_regs) { +#ifdef CONFIG_USE_IRQ + int irq = next_irq(); + + IRQ_HANDLER[irq].m_func(IRQ_HANDLER[irq].m_data); +#else printf ("interrupt request\n"); show_regs (pt_regs); bad_mode (); +#endif } - int interrupt_init (void) { - /* nothing happens here - we don't setup any IRQs */ +#ifdef CONFIG_USE_IRQ + int i; + + /* install default interrupt handlers */ + for (i = 0; i < N_IRQS; i++) { + IRQ_HANDLER[i].m_data = (void *)i; + IRQ_HANDLER[i].m_func = default_isr; + } + + /* install interrupt handler for timer */ + IRQ_HANDLER[IXP425_TIMER_2_IRQ].m_data = (void *)×tamp; + IRQ_HANDLER[IXP425_TIMER_2_IRQ].m_func = timer_isr; + + /* setup the Timer counter value */ + *IXP425_OSRT2 = (LATCH & ~IXP425_OST_RELOAD_MASK) | IXP425_OST_ENABLE; + + /* configure interrupts for IRQ mode */ + *IXP425_ICLR = 0x00000000; + + /* enable timer irq */ + *IXP425_ICMR = (1 << IXP425_TIMER_2_IRQ); +#endif + return (0); } |