1/* 2 * Interrupt controller driver for Xilinx Virtex-II Pro. 3 * 4 * Author: MontaVista Software, Inc. 5 * source@mvista.com 6 * 7 * 2002-2004 (c) MontaVista Software, Inc. This file is licensed under 8 * the terms of the GNU General Public License version 2. This program 9 * is licensed "as is" without any warranty of any kind, whether express 10 * or implied. 11 */ 12 13#include <linux/init.h> 14#include <linux/irq.h> 15#include <asm/io.h> 16#include <platforms/4xx/xparameters/xparameters.h> 17#include <asm/ibm4xx.h> 18#include <asm/machdep.h> 19 20/* No one else should require these constants, so define them locally here. */ 21#define ISR 0 /* Interrupt Status Register */ 22#define IPR 1 /* Interrupt Pending Register */ 23#define IER 2 /* Interrupt Enable Register */ 24#define IAR 3 /* Interrupt Acknowledge Register */ 25#define SIE 4 /* Set Interrupt Enable bits */ 26#define CIE 5 /* Clear Interrupt Enable bits */ 27#define IVR 6 /* Interrupt Vector Register */ 28#define MER 7 /* Master Enable Register */ 29 30#if XPAR_XINTC_USE_DCR == 0 31static volatile u32 *intc; 32#define intc_out_be32(addr, mask) out_be32((addr), (mask)) 33#define intc_in_be32(addr) in_be32((addr)) 34#else 35#define intc XPAR_INTC_0_BASEADDR 36#define intc_out_be32(addr, mask) mtdcr((addr), (mask)) 37#define intc_in_be32(addr) mfdcr((addr)) 38#endif 39 40static void 41xilinx_intc_enable(unsigned int irq) 42{ 43 unsigned long mask = (0x00000001 << (irq & 31)); 44 pr_debug("enable: %d\n", irq); 45 intc_out_be32(intc + SIE, mask); 46} 47 48static void 49xilinx_intc_disable(unsigned int irq) 50{ 51 unsigned long mask = (0x00000001 << (irq & 31)); 52 pr_debug("disable: %d\n", irq); 53 intc_out_be32(intc + CIE, mask); 54} 55 56static void 57xilinx_intc_disable_and_ack(unsigned int irq) 58{ 59 unsigned long mask = (0x00000001 << (irq & 31)); 60 pr_debug("disable_and_ack: %d\n", irq); 61 intc_out_be32(intc + CIE, mask); 62 if (!(irq_desc[irq].status & IRQ_LEVEL)) 63 intc_out_be32(intc + IAR, mask); /* ack edge triggered intr */ 64} 65 66static void 67xilinx_intc_end(unsigned int irq) 68{ 69 unsigned long mask = (0x00000001 << (irq & 31)); 70 71 pr_debug("end: %d\n", irq); 72 if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS))) { 73 intc_out_be32(intc + SIE, mask); 74 /* ack level sensitive intr */ 75 if (irq_desc[irq].status & IRQ_LEVEL) 76 intc_out_be32(intc + IAR, mask); 77 } 78} 79 80static struct hw_interrupt_type xilinx_intc = { 81 .typename = "Xilinx Interrupt Controller", 82 .enable = xilinx_intc_enable, 83 .disable = xilinx_intc_disable, 84 .ack = xilinx_intc_disable_and_ack, 85 .end = xilinx_intc_end, 86}; 87 88int 89xilinx_pic_get_irq(void) 90{ 91 int irq; 92 93 /* 94 * NOTE: This function is the one that needs to be improved in 95 * order to handle multiple interrupt controllers. It currently 96 * is hardcoded to check for interrupts only on the first INTC. 97 */ 98 99 irq = intc_in_be32(intc + IVR); 100 if (irq != -1) 101 irq = irq; 102 103 pr_debug("get_irq: %d\n", irq); 104 105 return (irq); 106} 107 108void __init 109ppc4xx_pic_init(void) 110{ 111 int i; 112 113 /* 114 * NOTE: The assumption here is that NR_IRQS is 32 or less 115 * (NR_IRQS is 32 for PowerPC 405 cores by default). 116 */ 117#if (NR_IRQS > 32) 118#error NR_IRQS > 32 not supported 119#endif 120 121#if XPAR_XINTC_USE_DCR == 0 122 intc = ioremap(XPAR_INTC_0_BASEADDR, 32); 123 124 printk(KERN_INFO "Xilinx INTC #0 at 0x%08lX mapped to 0x%08lX\n", 125 (unsigned long) XPAR_INTC_0_BASEADDR, (unsigned long) intc); 126#else 127 printk(KERN_INFO "Xilinx INTC #0 at 0x%08lX (DCR)\n", 128 (unsigned long) XPAR_INTC_0_BASEADDR); 129#endif 130 131 /* 132 * Disable all external interrupts until they are 133 * explicitly requested. 134 */ 135 intc_out_be32(intc + IER, 0); 136 137 /* Acknowledge any pending interrupts just in case. */ 138 intc_out_be32(intc + IAR, ~(u32) 0); 139 140 /* Turn on the Master Enable. */ 141 intc_out_be32(intc + MER, 0x3UL); 142 143 ppc_md.get_irq = xilinx_pic_get_irq; 144 145 for (i = 0; i < NR_IRQS; ++i) { 146 irq_desc[i].chip = &xilinx_intc; 147 148 if (XPAR_INTC_0_KIND_OF_INTR & (0x00000001 << i)) 149 irq_desc[i].status &= ~IRQ_LEVEL; 150 else 151 irq_desc[i].status |= IRQ_LEVEL; 152 } 153} 154