version 1.1, 2007/11/24 20:49:44 |
version 1.2, 2007/12/16 23:20:31 |
|
|
#include <arch/sam7s64/dev/at91sam7.h> |
#include <arch/sam7s64/dev/at91sam7.h> |
#include <libkern/printf.h> |
#include <libkern/printf.h> |
|
|
#define SAAIC_DEBUG |
#define SAAIC_DEBUG |
|
|
#ifdef SAAIC_DEBUG |
#ifdef SAAIC_DEBUG |
#define DPRINTF(x...) do { printf(x); } while (0) |
#define DPRINTF(x...) do { printf(x); } while (0) |
|
|
* Advanced Interrupt Controller. |
* Advanced Interrupt Controller. |
*/ |
*/ |
extern void (*irq_trampoline_func)(void); |
extern void (*irq_trampoline_func)(void); |
|
extern struct intr_vector *irqtable; |
struct saaic_dd *irqcdd; /* current irqc device */ |
struct saaic_dd *irqcdd; /* current irqc device */ |
|
|
struct driver saaic_dr = { |
struct driver saaic_dr = { |
|
|
saaic_attach(struct device *self, uint32_t loc, uint8_t flags) |
saaic_attach(struct device *self, uint32_t loc, uint8_t flags) |
{ |
{ |
struct saaic_dd *ddp = self->dv_devdata; |
struct saaic_dd *ddp = self->dv_devdata; |
uint8_t intrno; |
uint8_t intrno; |
|
struct intr_vector *ivp = irqtable; |
|
|
/* leap to parent's bus_handle */ |
/* leap to parent's bus_handle */ |
ddp->sa_bhp = self->dv_parent->dv_aux; |
ddp->sa_bhp = self->dv_parent->dv_aux; |
|
|
for (intrno = 0; intrno < 32; intrno++) |
for (intrno = 0; intrno < 32; intrno++) |
saaic_unmask_intr(intrno); |
saaic_unmask_intr(intrno); |
|
|
|
/* clear all interrupts */ |
|
for (intrno = 0; intrno < 32; intrno++) |
|
saaic_clear_intr(intrno); |
|
|
|
/* look in system irqtable for claimed interrupts and unmask them */ |
|
while(ivp != NULL) { |
|
saaic_unmask_intr(ivp->iv_intrno); |
|
|
|
ivp = ivp->iv_next; |
|
} |
|
|
__cpu_enable_irq(); |
__cpu_enable_irq(); |
|
|
return(0); |
return(0); |
|
|
} |
} |
|
|
|
|
|
void |
|
saaic_clear_intr(uint8_t intrno) |
|
{ |
|
bus_write_1(irqcdd->sa_bhp, (uint32_t)AT91C_AIC_ICCR, 1 << intrno); |
|
DPRINTF("saaic_clear_intr: cleared interrupt no. %d (status=0x%x)\n", intrno, saaic_intrstatus()); |
|
} |
|
|
|
|
|
void |
|
saaic_ack_intr(void) |
|
{ |
|
bus_write_1(irqcdd->sa_bhp, (uint32_t)AT91C_AIC_EOICR, 1); |
|
DPRINTF("saaic_ack_intr: acknowledged current interrupt (status=0x%x)\n", saaic_intrstatus()); |
|
} |
|
|
|
|
|
|
uint32_t |
uint32_t |
saaic_intrstatus(void) |
saaic_intrstatus(void) |
{ |
{ |
return( bus_read_4(irqcdd->sa_bhp, (uint32_t)AT91C_AIC_IMR)); |
return( bus_read_4(irqcdd->sa_bhp, (uint32_t)AT91C_AIC_IPR)); |
} |
} |
|
|
|
|
|
|
/* read intr status; one bit per intr source */ |
/* read intr status; one bit per intr source */ |
irqstatus = saaic_intrstatus(); |
irqstatus = saaic_intrstatus(); |
|
|
DPRINTF("saaic_irq: got interrupt (status=0x%x)\n", irqstatus); |
DPRINTF("saaic_irq: got interrupt (pending mask=0x%x)\n", irqstatus); |
|
|
/* exit if no interrupts; should not happen */ |
/* exit if no interrupts; should not happen */ |
if (irqstatus == 0) |
// if (irqstatus == 0) |
return; |
// return; |
|
|
/* let kern_irq throw us to the right place */ |
/* let kern_irq throw us to the right place */ |
for (intrno = 0; intrno < 32; intrno++) |
for (intrno = 0; intrno < 32; intrno++) |
if (irqstatus & (1 << intrno)) { |
if (irqstatus & (1 << intrno)) { |
/* interrupt line is active */ |
/* interrupt line is active */ |
intr_execute(intrno); |
intr_execute(intrno); |
|
|
|
/* XXX */ |
|
saaic_clear_intr(intrno); |
|
|
|
/* XXX acknowledge this interrupt */ |
|
saaic_ack_intr(); |
} |
} |
|
|
} |
} |