Hi all, I'm writing a simple driver to test IRQ handling on the AMCC Yosemite board. The board has an 8x2 header with several GPIO pins, a number of which can be configured as IRQ inputs.
I have setup GPIO46 as output, and GPIO47 as input, and selected IRQ8 on that pin. The simple driver sets up the IRQ handler, and then drops into a loop where it pulses the GPIO47 output. The relevent messages from this loop are: - Read some GPIO1 registers - GPIO1_OR = 0x00020000 - GPIO1_TCR = 0xC2020000 - GPIO1_ISR1L = 0x00000401 - enable IRQ8 - UIC1_SR = 0x00002800 - UIC1_ER = 0xE0801008 IRQ8 is bit 19 in the enable register, i.e., 1 << (31-19) = 1000h So, clearly its enabled here. - sleep for 1s - UIC1_SR = 0x00002800 - UIC1_ER = 0xE0801008 And after a sleep for 1s its still enabled. ----- loop test ----- - generate low on GPIO46 - sleep for 10 ticks - generate high on GPIO46 - UIC1_SR = 0x00003800 - UIC1_ER = 0xE0800008 - IRQ8 status is set, clearing it - UIC1_SR = 0x00002800 - UIC1_ER = 0xE0800008 - sleep for 10 ticks ... repeats ... The low pulse on the GPIO46 pin definitely set the IRQ8 status bit, but why on earth is the enable bit cleared! (I added the check for the status bit being set, since my IRQ handler was not getting called) To enable the IRQ8 line, I simply accessed the UIC1_ER register directly via reg = mfdcr(DCRN_UIC_ER(UIC1)); reg |= 1 << (31-19); mtdcr(DCRN_UIC_ER(UIC1), reg); So, is there a kernel wide interrupt enable mask that I really should be using? Or, an interrupt enable API? I initially thought that when I registered an interrupt using request_irq() that the kernel would go off an enable the requested IRQ, but this test shows that it did not. Any ideas? Cheers Dave --------------- driver code -------------------------- /* yosemite_irq.c */ #include <linux/module.h> /* kernel modules */ #include <linux/interrupt.h>/* request_irq(), etc */ #include <asm/io.h> /* ioremap64(), iounmap(), readl() */ static char *name = "yosemite_irq"; static unsigned long long base = 0x0EF600C00; // 36-bit address static unsigned int size = 0x44; static char *kernel; static int irq = 8; static irqreturn_t simple_irq_handler(int irq, void *dev_id, struct pt_regs *regs) { int *p = (int *)kernel; printk("<irq %d> received!\n", irq); /* Deassert the interrupt input; GPIO1_OR[14] = 1 */ // writel(1<<(31-14), kernel); p[0] = 1 << (31-14); /* Clear IRQ8 status (UIC1_SR[19] = 1 to clear it) */ mtdcr(DCRN_UIC_SR(UIC1), 1 << (31-19)); return IRQ_HANDLED; } static int __init simple_init(void) { int status; int reg; int *p; int i; printk("<init> called.\n"); /* Get the GPIO control registers */ printk(" - remap the GPIO registers\n"); kernel = ioremap64(base, size); printk(" - remapped to address 0x%.8X\n", (int)kernel); p = (int *)kernel; /* Get the IRQ8 */ printk(" - request the IRQ\n"); status = request_irq( irq, simple_irq_handler, SA_INTERRUPT, name, 0); if (status < 0) { printk(" - request for irq %d failed\n", irq); return status; } printk(" - Read some DCR registers\n"); printk(" - UIC0_SR = 0x%.8X\n", mfdcr(DCRN_UIC_SR(UIC0))); printk(" - UIC0_ER = 0x%.8X\n", mfdcr(DCRN_UIC_ER(UIC0))); printk(" - UIC0_PR = 0x%.8X\n", mfdcr(DCRN_UIC_PR(UIC0))); printk(" - UIC0_TR = 0x%.8X\n", mfdcr(DCRN_UIC_TR(UIC0))); printk(" - UIC1_SR = 0x%.8X\n", mfdcr(DCRN_UIC_SR(UIC1))); printk(" - UIC1_ER = 0x%.8X\n", mfdcr(DCRN_UIC_ER(UIC1))); printk(" - UIC1_PR = 0x%.8X\n", mfdcr(DCRN_UIC_PR(UIC1))); printk(" - UIC1_TR = 0x%.8X\n", mfdcr(DCRN_UIC_TR(UIC1))); printk(" - Read some GPIO1 registers\n"); printk(" - GPIO1_OR = 0x%.8X\n", p[0]); printk(" - GPIO1_TCR = 0x%.8X\n", p[1]); printk(" - GPIO1_ISR1L = 0x%.8X\n", p[12]); /* Setup GPIO46 as output. GPIO46 drives GPIO47, and * GPIO47 will be used as IRQ8. The default IRQ * sensitivity is low and level sensitive. */ printk(" - set GPIO46 as output\n"); /* GPIO1_OR[14] = 1 */ // writel(readl(kernel) | (1 << (31-14)), kernel); p[0] |= 1 << (31-14); /* GPIO1_TCR[14] = 1 */ // writel(readl(kernel+0x04) | (1 << (31-14)), kernel+0x04); p[1] |= 1 << (31-14); /* Select GPIO47 IRQ8 input */ printk(" - set GPIO47 as IRQ8 input\n"); /* GPIO1_ISR1L[30:31] = 01b */ // writel(readl(kernel+0x30) | 1, kernel+0x30); p[12] |= 1; /* Clear IRQ8 status (write 1 to bit 19 to clear it) */ printk(" - clear IRQ8 status\n"); mtdcr(DCRN_UIC_SR(UIC1), 1 << (31-19)); printk(" - Read some GPIO1 registers\n"); printk(" - GPIO1_OR = 0x%.8X\n", p[0]); printk(" - GPIO1_TCR = 0x%.8X\n", p[1]); printk(" - GPIO1_ISR1L = 0x%.8X\n", p[12]); /* Enable IRQ8 */ printk(" - enable IRQ8\n"); reg = mfdcr(DCRN_UIC_ER(UIC1)); reg |= 1 << (31-19); mtdcr(DCRN_UIC_ER(UIC1), reg); printk(" - UIC1_SR = 0x%.8X\n", mfdcr(DCRN_UIC_SR(UIC1))); printk(" - UIC1_ER = 0x%.8X\n", mfdcr(DCRN_UIC_ER(UIC1))); printk(" - sleep for 1s\n"); set_current_state(TASK_INTERRUPTIBLE); schedule_timeout(HZ); printk(" - UIC1_SR = 0x%.8X\n", mfdcr(DCRN_UIC_SR(UIC1))); printk(" - UIC1_ER = 0x%.8X\n", mfdcr(DCRN_UIC_ER(UIC1))); reg = mfdcr(DCRN_UIC_ER(UIC1)); if ((reg & (1 << (31-19))) == 0) { printk(" - hey something cleared my enable bit!\n"); return 0; } printk(" ----- loop test -----\n"); for (i = 0; i < 5; i++) { printk(" - generate low on GPIO46\n"); p[0] = 0; printk(" - sleep for 10 ticks\n"); set_current_state(TASK_INTERRUPTIBLE); schedule_timeout(10); printk(" - generate high on GPIO46\n"); p[0] = 1 << (31-14); printk(" - UIC1_SR = 0x%.8X\n", mfdcr(DCRN_UIC_SR(UIC1))); printk(" - UIC1_ER = 0x%.8X\n", mfdcr(DCRN_UIC_ER(UIC1))); reg = mfdcr(DCRN_UIC_SR(UIC1)); if ((reg & (1 << (31-19))) == 0) { printk(" - IRQ8 status is not set\n"); } else { printk(" - IRQ8 status is set, clearing it\n"); mtdcr(DCRN_UIC_SR(UIC1), 1 << (31-19)); } printk(" - UIC1_SR = 0x%.8X\n", mfdcr(DCRN_UIC_SR(UIC1))); printk(" - UIC1_ER = 0x%.8X\n", mfdcr(DCRN_UIC_ER(UIC1))); printk(" - sleep for 10 ticks\n"); set_current_state(TASK_INTERRUPTIBLE); schedule_timeout(10); } /* log load */ printk("module loaded.\n"); return 0; } void __exit simple_exit(void) { int reg; printk("<exit> called.\n"); /* Disable IRQ8 */ reg = mfdcr(DCRN_UIC_ER(UIC1)); reg &= ~(1 << (31-19)); mtdcr(DCRN_UIC_ER(UIC1), reg); free_irq(irq, 0); iounmap(kernel); printk("module unloaded\n"); } module_init(simple_init); module_exit(simple_exit);