File: [local] / funnyos / arch / testarm / dev / tairqc.c (download)
Revision 1.7, Mon Nov 5 20:11:25 2007 UTC (16 years, 7 months ago) by init
Branch: MAIN
CVS Tags: HEAD Changes since 1.6: +2 -2 lines
undef TAIRQC_DEBUG; testarm irq controller seems work fine
|
/*
* $Id: tairqc.c,v 1.7 2007/11/05 20:11:25 init Exp $
*/
#include <sys/types.h>
#include <sys/device.h>
#include <sys/bus.h>
#include <sys/kern_irq.h>
#include <dev/cpuvar.h>
#include <arch/testarm/dev/tairqcvar.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.
*/
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);
extern void (*irq_trampoline_func)(void);
struct tairqc_dd *irqcdd; /* current irq device */
struct driver tairqc_dr = {
sizeof(struct tairqc_dd),
tairqc_attach,
NULL,
NULL
};
int
tairqc_attach(struct device *self, uint32_t loc, uint8_t flags)
{
struct tairqc_dd *ddp = self->dv_devdata;
uint8_t intrno;
/* leap to parent's bus_handle */
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
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)
{
/*
* 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);
}
}