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

File: [local] / funnyos / arch / testarm / dev / tairqc.c (download)

Revision 1.7, Mon Nov 5 20:11:25 2007 UTC (16 years, 6 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);
		}

}