[BACK]Return to saaic.c CVS log [TXT][DIR] Up to [local] / funnyos / arch / sam7s64 / dev

File: [local] / funnyos / arch / sam7s64 / dev / saaic.c (download)

Revision 1.1, Sat Nov 24 20:49:44 2007 UTC (16 years, 6 months ago) by nbrk
Branch: MAIN

Advanced Interrupt Controller support;
still not complete

/*
 * $Id: saaic.c,v 1.1 2007/11/24 20:49:44 nbrk Exp $
 */
#include <sys/types.h>
#include <sys/device.h>
#include <sys/bus.h>
#include <sys/kern_irq.h>

#include <dev/cpuvar.h>

#include <arch/sam7s64/dev/saaicvar.h>
#include <arch/sam7s64/dev/at91sam7.h>
#include <libkern/printf.h>

#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);
		}

}