[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.6, Sun Nov 4 23:15:57 2007 UTC (16 years, 6 months ago) by init
Branch: MAIN
Changes since 1.5: +27 -3 lines

add minimal code to tartc_irq(), our trampoline from low-level IRQ isr:
 upon entering (when core IRQ is asserted) we read irq status from tairqc and execute
  interrupt handler for every intrno in tairqc status register.
be sure to mask all (really all) unwanted interrupts on attachment;
explicitly unmask intr no. 4 (Real Time Clock) so we can see if it all is working or not :)

this completes irq-related chain:
RTC -intr-> IRQC -irq-> CPU Core enters IRQ_mode and jumps to 0x00000018 (_vector_irq):
_vector_irq -> irq_trampoline -> irq_trampoline_func (which is tairqc_irq) -> tairqc_irq (read irqc status)
 -> (execute interrupt handlers for every source) -> tartc_interrupt()

/*
 * $Id: tairqc.c,v 1.6 2007/11/04 23:15:57 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);
		}

}