[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.2, Sun Dec 16 23:20:31 2007 UTC (16 years, 5 months ago) by nbrk
Branch: MAIN
CVS Tags: HEAD
Changes since 1.1: +43 -7 lines

add saaic_clear_intr() and saaic_ack_intr(); shuffle code a bit;
still half functional (and SAAIC_DEBUG is on by default)

/*
 * $Id: saaic.c,v 1.2 2007/12/16 23:20:31 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);
extern struct intr_vector *irqtable;
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;	
	struct intr_vector *ivp = irqtable;

	/* 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);

	/* 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();

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


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
saaic_intrstatus(void)
{
	return( bus_read_4(irqcdd->sa_bhp, (uint32_t)AT91C_AIC_IPR));
}


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 (pending mask=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);

			/* XXX */
			saaic_clear_intr(intrno);

			/* XXX acknowledge this interrupt */
			saaic_ack_intr();
		}

}