/* * $Id: saaic.c,v 1.1 2007/11/24 20:49:44 nbrk Exp $ */ #include #include #include #include #include #include #include #include #define SAAIC_DEBUG #ifdef SAAIC_DEBUG #define DPRINTF(x...) do { printf(x); } while (0) #else #define DPRINTF(x...) { } #endif /* * Advanced Interrupt Controller. */ extern void (*irq_trampoline_func)(void); struct saaic_dd *irqcdd; /* current irqc device */ struct driver saaic_dr = { sizeof(struct saaic_dd), saaic_attach, NULL, NULL }; int saaic_attach(struct device *self, uint32_t loc, uint8_t flags) { struct saaic_dd *ddp = self->dv_devdata; uint8_t intrno; /* leap to parent's bus_handle */ ddp->sa_bhp = self->dv_parent->dv_aux; /* make this controller default */ irqcdd = ddp; printf("SAM7 Advanced Interrupt Controller (32 sources, 8 pri_levels)\n"); /* override trampoline so core irq jumps to us */ irq_trampoline_func = saaic_irq; /* mask all interrupts */ for (intrno = 0; intrno < 32; intrno++) saaic_unmask_intr(intrno); __cpu_enable_irq(); return(0); } void saaic_mask_intr(uint8_t intrno) { bus_write_4(irqcdd->sa_bhp, (uint32_t)AT91C_AIC_IDCR, 1 << intrno); DPRINTF("saaic_mask_intr: masked interrupt no. %d (status=0x%x)\n", intrno, saaic_intrstatus()); } void saaic_unmask_intr(uint8_t intrno) { bus_write_1(irqcdd->sa_bhp, (uint32_t)AT91C_AIC_IECR, 1 << intrno); DPRINTF("saaic_unmask_intr: unmasked interrupt no. %d (status=0x%x)\n", intrno, saaic_intrstatus()); } uint32_t saaic_intrstatus(void) { return( bus_read_4(irqcdd->sa_bhp, (uint32_t)AT91C_AIC_IMR)); } void saaic_irq(void) { /* * Process an IRQ. * Check interrupt status of the irqc and execute corresponding intr handlers. */ uint32_t irqstatus; uint8_t intrno; /* read intr status; one bit per intr source */ irqstatus = saaic_intrstatus(); DPRINTF("saaic_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); } }