Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v2.6.26-rc6 157 lines 4.0 kB view raw
1/* 2 * Interrupt controller driver for Xilinx Virtex FPGAs 3 * 4 * Copyright (C) 2007 Secret Lab Technologies Ltd. 5 * 6 * This file is licensed under the terms of the GNU General Public License 7 * version 2. This program is licensed "as is" without any warranty of any 8 * kind, whether express or implied. 9 * 10 */ 11 12/* 13 * This is a driver for the interrupt controller typically found in 14 * Xilinx Virtex FPGA designs. 15 * 16 * The interrupt sense levels are hard coded into the FPGA design with 17 * typically a 1:1 relationship between irq lines and devices (no shared 18 * irq lines). Therefore, this driver does not attempt to handle edge 19 * and level interrupts differently. 20 */ 21#undef DEBUG 22 23#include <linux/kernel.h> 24#include <linux/irq.h> 25#include <linux/of.h> 26#include <asm/io.h> 27#include <asm/processor.h> 28#include <asm/irq.h> 29 30/* 31 * INTC Registers 32 */ 33#define XINTC_ISR 0 /* Interrupt Status */ 34#define XINTC_IPR 4 /* Interrupt Pending */ 35#define XINTC_IER 8 /* Interrupt Enable */ 36#define XINTC_IAR 12 /* Interrupt Acknowledge */ 37#define XINTC_SIE 16 /* Set Interrupt Enable bits */ 38#define XINTC_CIE 20 /* Clear Interrupt Enable bits */ 39#define XINTC_IVR 24 /* Interrupt Vector */ 40#define XINTC_MER 28 /* Master Enable */ 41 42static struct irq_host *master_irqhost; 43 44/* 45 * IRQ Chip operations 46 */ 47static void xilinx_intc_mask(unsigned int virq) 48{ 49 int irq = virq_to_hw(virq); 50 void * regs = get_irq_chip_data(virq); 51 pr_debug("mask: %d\n", irq); 52 out_be32(regs + XINTC_CIE, 1 << irq); 53} 54 55static void xilinx_intc_unmask(unsigned int virq) 56{ 57 int irq = virq_to_hw(virq); 58 void * regs = get_irq_chip_data(virq); 59 pr_debug("unmask: %d\n", irq); 60 out_be32(regs + XINTC_SIE, 1 << irq); 61} 62 63static void xilinx_intc_ack(unsigned int virq) 64{ 65 int irq = virq_to_hw(virq); 66 void * regs = get_irq_chip_data(virq); 67 pr_debug("ack: %d\n", irq); 68 out_be32(regs + XINTC_IAR, 1 << irq); 69} 70 71static struct irq_chip xilinx_intc_irqchip = { 72 .typename = "Xilinx INTC", 73 .mask = xilinx_intc_mask, 74 .unmask = xilinx_intc_unmask, 75 .ack = xilinx_intc_ack, 76}; 77 78/* 79 * IRQ Host operations 80 */ 81static int xilinx_intc_map(struct irq_host *h, unsigned int virq, 82 irq_hw_number_t irq) 83{ 84 set_irq_chip_data(virq, h->host_data); 85 set_irq_chip_and_handler(virq, &xilinx_intc_irqchip, handle_level_irq); 86 set_irq_type(virq, IRQ_TYPE_NONE); 87 return 0; 88} 89 90static struct irq_host_ops xilinx_intc_ops = { 91 .map = xilinx_intc_map, 92}; 93 94struct irq_host * __init 95xilinx_intc_init(struct device_node *np) 96{ 97 struct irq_host * irq; 98 struct resource res; 99 void * regs; 100 int rc; 101 102 /* Find and map the intc registers */ 103 rc = of_address_to_resource(np, 0, &res); 104 if (rc) { 105 printk(KERN_ERR __FILE__ ": of_address_to_resource() failed\n"); 106 return NULL; 107 } 108 regs = ioremap(res.start, 32); 109 110 printk(KERN_INFO "Xilinx intc at 0x%08LX mapped to 0x%p\n", 111 res.start, regs); 112 113 /* Setup interrupt controller */ 114 out_be32(regs + XINTC_IER, 0); /* disable all irqs */ 115 out_be32(regs + XINTC_IAR, ~(u32) 0); /* Acknowledge pending irqs */ 116 out_be32(regs + XINTC_MER, 0x3UL); /* Turn on the Master Enable. */ 117 118 /* Allocate and initialize an irq_host structure. */ 119 irq = irq_alloc_host(np, IRQ_HOST_MAP_LINEAR, 32, &xilinx_intc_ops, -1); 120 if (!irq) 121 panic(__FILE__ ": Cannot allocate IRQ host\n"); 122 irq->host_data = regs; 123 return irq; 124} 125 126int xilinx_intc_get_irq(void) 127{ 128 void * regs = master_irqhost->host_data; 129 pr_debug("get_irq:\n"); 130 return irq_linear_revmap(master_irqhost, in_be32(regs + XINTC_IVR)); 131} 132 133void __init xilinx_intc_init_tree(void) 134{ 135 struct device_node *np; 136 137 /* find top level interrupt controller */ 138 for_each_compatible_node(np, NULL, "xlnx,opb-intc-1.00.c") { 139 if (!of_get_property(np, "interrupts", NULL)) 140 break; 141 } 142 if (!np) { 143 for_each_compatible_node(np, NULL, "xlnx,xps-intc-1.00.a") { 144 if (!of_get_property(np, "interrupts", NULL)) 145 break; 146 } 147 } 148 149 /* xilinx interrupt controller needs to be top level */ 150 BUG_ON(!np); 151 152 master_irqhost = xilinx_intc_init(np); 153 BUG_ON(!master_irqhost); 154 155 irq_set_default_host(master_irqhost); 156 of_node_put(np); 157}