version 1.1, 2007/10/29 20:12:18 |
version 1.6, 2007/11/04 23:15:57 |
|
|
#include <sys/types.h> |
#include <sys/types.h> |
#include <sys/device.h> |
#include <sys/device.h> |
#include <sys/bus.h> |
#include <sys/bus.h> |
|
#include <sys/kern_irq.h> |
|
|
|
#include <dev/cpuvar.h> |
|
|
#include <arch/testarm/dev/tairqcvar.h> |
#include <arch/testarm/dev/tairqcvar.h> |
#include <arch/testarm/dev/tairqcreg.h> |
#include <arch/testarm/dev/tairqcreg.h> |
|
#include <libkern/printf.h> |
|
|
|
#define TAIRQC_DEBUG |
|
|
|
#ifdef TAIRQC_DEBUG |
|
#define DPRINTF(x...) do { printf(x); } while (0) |
|
#else |
|
#define DPRINTF(x...) { } |
|
#endif |
|
|
/* |
/* |
* testarm Interrupt Controller Unit support. |
* testarm Interrupt Controller Unit support. |
*/ |
*/ |
int tairqc_attach(struct device *self, uint32_t loc, uint8_t flags); |
int tairqc_attach(struct device *self, uint32_t loc, uint8_t flags); |
|
void tairqc_mask_intr(uint8_t intrno); |
|
void tairqc_unmask_intr(uint8_t intrno); |
|
uint32_t tairqc_intrstatus(void); |
void tairqc_irq(void); |
void tairqc_irq(void); |
|
|
|
extern void (*irq_trampoline_func)(void); |
|
struct tairqc_dd *irqcdd; /* current irq device */ |
|
|
struct driver tairqc_dr = { |
struct driver tairqc_dr = { |
sizeof(struct tairqc_dd), |
sizeof(struct tairqc_dd), |
tairqc_attach, |
tairqc_attach, |
|
NULL, |
NULL |
NULL |
}; |
}; |
|
|
|
|
tairqc_attach(struct device *self, uint32_t loc, uint8_t flags) |
tairqc_attach(struct device *self, uint32_t loc, uint8_t flags) |
{ |
{ |
struct tairqc_dd *ddp = self->dv_devdata; |
struct tairqc_dd *ddp = self->dv_devdata; |
|
uint8_t intrno; |
|
|
/* leap to parent's bus_handle */ |
/* leap to parent's bus_handle */ |
ddp->td_bushandlep = self->dv_parent->dv_aux; |
ddp->td_bushandlep = self->dv_parent->dv_aux; |
|
|
|
/* save locator */ |
|
ddp->td_ioaddr = loc ? loc : TAIRQC_REG_BASE; |
|
|
|
irqcdd = ddp; |
|
|
|
printf("testarm IRQ Controller (2=cons, 3=ether, 4=rtc, 6=mp)\n"); |
|
|
|
/* override trampoline so core irq jumps to us */ |
|
irq_trampoline_func = tairqc_irq; |
|
|
|
/* mask all interrupts */ |
|
for (intrno = 0; intrno < 32; intrno++) |
|
tairqc_mask_intr(intrno); |
|
|
|
/* XXX unmask rtc intr */ |
|
tairqc_unmask_intr(4); |
|
|
|
__cpu_enable_irq(); |
|
|
|
return(0); |
} |
} |
|
|
|
|
void |
void |
|
tairqc_mask_intr(uint8_t intrno) |
|
{ |
|
bus_write_1(irqcdd->td_bushandlep, irqcdd->td_ioaddr + TAIRQC_OFF_IRQMASK, intrno); |
|
DPRINTF("tairqc_mask_intr: masked interrupt no. %d (status=0x%x)\n", intrno, tairqc_intrstatus()); |
|
} |
|
|
|
|
|
void |
|
tairqc_unmask_intr(uint8_t intrno) |
|
{ |
|
bus_write_1(irqcdd->td_bushandlep, irqcdd->td_ioaddr + TAIRQC_OFF_IRQUNMASK, intrno); |
|
DPRINTF("tairqc_unmask_intr: unmasked interrupt no. %d (status=0x%x)\n", intrno, tairqc_intrstatus()); |
|
} |
|
|
|
|
|
uint32_t |
|
tairqc_intrstatus(void) |
|
{ |
|
bus_read_4(irqcdd->td_bushandlep, irqcdd->td_ioaddr + TAIRQC_OFF_IRQSTATUS); |
|
} |
|
|
|
|
|
void |
tairqc_irq(void) |
tairqc_irq(void) |
{ |
{ |
/* |
/* |
* Process an IRQ |
* Process an IRQ. |
|
* Check interrupt status of the irqc and execute corresponding intr handlers |
|
* for every asserted interrupt source (could be 0...31 on tairqc) |
*/ |
*/ |
|
uint32_t irqstatus; |
|
uint8_t intrno; |
|
|
|
/* read intr status; one bit per intr source */ |
|
irqstatus = tairqc_intrstatus(); |
|
|
|
DPRINTF("tairqc_irq: got interrupt (status=0x%x)\n", irqstatus); |
|
|
|
/* exit if no interrupts; should not happen */ |
|
if (irqstatus == 0) |
|
return; |
|
|
|
/* let kern_irq throw us to the right place */ |
|
for (intrno = 0; intrno < 32; intrno++) |
|
if (irqstatus & (1 << intrno)) { |
|
/* interrupt line is active */ |
|
intr_execute(intrno); |
|
} |
|
|
} |
} |
|
|