1 /* 2 * Copyright (C) 2008 Ilya Yanok, Emcraft Systems 3 * 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License version 2 as 7 * published by the Free Software Foundation. 8 * 9 */ 10 11 #include <linux/irq.h> 12 #include <linux/of_platform.h> 13 #include <linux/io.h> 14 15 /* 16 * The FPGA supports 9 interrupt sources, which can be routed to 3 17 * interrupt request lines of the MPIC. The line to be used can be 18 * specified through the third cell of FDT property "interrupts". 19 */ 20 21 #define SOCRATES_FPGA_NUM_IRQS 9 22 23 #define FPGA_PIC_IRQCFG (0x0) 24 #define FPGA_PIC_IRQMASK(n) (0x4 + 0x4 * (n)) 25 26 #define SOCRATES_FPGA_IRQ_MASK ((1 << SOCRATES_FPGA_NUM_IRQS) - 1) 27 28 struct socrates_fpga_irq_info { 29 unsigned int irq_line; 30 int type; 31 }; 32 33 /* 34 * Interrupt routing and type table 35 * 36 * IRQ_TYPE_NONE means the interrupt type is configurable, 37 * otherwise it's fixed to the specified value. 38 */ 39 static struct socrates_fpga_irq_info fpga_irqs[SOCRATES_FPGA_NUM_IRQS] = { 40 [0] = {0, IRQ_TYPE_NONE}, 41 [1] = {0, IRQ_TYPE_LEVEL_HIGH}, 42 [2] = {0, IRQ_TYPE_LEVEL_LOW}, 43 [3] = {0, IRQ_TYPE_NONE}, 44 [4] = {0, IRQ_TYPE_NONE}, 45 [5] = {0, IRQ_TYPE_NONE}, 46 [6] = {0, IRQ_TYPE_NONE}, 47 [7] = {0, IRQ_TYPE_NONE}, 48 [8] = {0, IRQ_TYPE_LEVEL_HIGH}, 49 }; 50 51 #define socrates_fpga_irq_to_hw(virq) ((unsigned int)irq_map[virq].hwirq) 52 53 static DEFINE_SPINLOCK(socrates_fpga_pic_lock); 54 55 static void __iomem *socrates_fpga_pic_iobase; 56 static struct irq_host *socrates_fpga_pic_irq_host; 57 static unsigned int socrates_fpga_irqs[3]; 58 59 static inline uint32_t socrates_fpga_pic_read(int reg) 60 { 61 return in_be32(socrates_fpga_pic_iobase + reg); 62 } 63 64 static inline void socrates_fpga_pic_write(int reg, uint32_t val) 65 { 66 out_be32(socrates_fpga_pic_iobase + reg, val); 67 } 68 69 static inline unsigned int socrates_fpga_pic_get_irq(unsigned int irq) 70 { 71 uint32_t cause; 72 unsigned long flags; 73 int i; 74 75 /* Check irq line routed to the MPIC */ 76 for (i = 0; i < 3; i++) { 77 if (irq == socrates_fpga_irqs[i]) 78 break; 79 } 80 if (i == 3) 81 return NO_IRQ; 82 83 spin_lock_irqsave(&socrates_fpga_pic_lock, flags); 84 cause = socrates_fpga_pic_read(FPGA_PIC_IRQMASK(i)); 85 spin_unlock_irqrestore(&socrates_fpga_pic_lock, flags); 86 for (i = SOCRATES_FPGA_NUM_IRQS - 1; i >= 0; i--) { 87 if (cause >> (i + 16)) 88 break; 89 } 90 return irq_linear_revmap(socrates_fpga_pic_irq_host, 91 (irq_hw_number_t)i); 92 } 93 94 void socrates_fpga_pic_cascade(unsigned int irq, struct irq_desc *desc) 95 { 96 unsigned int cascade_irq; 97 98 /* 99 * See if we actually have an interrupt, call generic handling code if 100 * we do. 101 */ 102 cascade_irq = socrates_fpga_pic_get_irq(irq); 103 104 if (cascade_irq != NO_IRQ) 105 generic_handle_irq(cascade_irq); 106 desc->chip->eoi(irq); 107 108 } 109 110 static void socrates_fpga_pic_ack(unsigned int virq) 111 { 112 unsigned long flags; 113 unsigned int hwirq, irq_line; 114 uint32_t mask; 115 116 hwirq = socrates_fpga_irq_to_hw(virq); 117 118 irq_line = fpga_irqs[hwirq].irq_line; 119 spin_lock_irqsave(&socrates_fpga_pic_lock, flags); 120 mask = socrates_fpga_pic_read(FPGA_PIC_IRQMASK(irq_line)) 121 & SOCRATES_FPGA_IRQ_MASK; 122 mask |= (1 << (hwirq + 16)); 123 socrates_fpga_pic_write(FPGA_PIC_IRQMASK(irq_line), mask); 124 spin_unlock_irqrestore(&socrates_fpga_pic_lock, flags); 125 } 126 127 static void socrates_fpga_pic_mask(unsigned int virq) 128 { 129 unsigned long flags; 130 unsigned int hwirq; 131 int irq_line; 132 u32 mask; 133 134 hwirq = socrates_fpga_irq_to_hw(virq); 135 136 irq_line = fpga_irqs[hwirq].irq_line; 137 spin_lock_irqsave(&socrates_fpga_pic_lock, flags); 138 mask = socrates_fpga_pic_read(FPGA_PIC_IRQMASK(irq_line)) 139 & SOCRATES_FPGA_IRQ_MASK; 140 mask &= ~(1 << hwirq); 141 socrates_fpga_pic_write(FPGA_PIC_IRQMASK(irq_line), mask); 142 spin_unlock_irqrestore(&socrates_fpga_pic_lock, flags); 143 } 144 145 static void socrates_fpga_pic_mask_ack(unsigned int virq) 146 { 147 unsigned long flags; 148 unsigned int hwirq; 149 int irq_line; 150 u32 mask; 151 152 hwirq = socrates_fpga_irq_to_hw(virq); 153 154 irq_line = fpga_irqs[hwirq].irq_line; 155 spin_lock_irqsave(&socrates_fpga_pic_lock, flags); 156 mask = socrates_fpga_pic_read(FPGA_PIC_IRQMASK(irq_line)) 157 & SOCRATES_FPGA_IRQ_MASK; 158 mask &= ~(1 << hwirq); 159 mask |= (1 << (hwirq + 16)); 160 socrates_fpga_pic_write(FPGA_PIC_IRQMASK(irq_line), mask); 161 spin_unlock_irqrestore(&socrates_fpga_pic_lock, flags); 162 } 163 164 static void socrates_fpga_pic_unmask(unsigned int virq) 165 { 166 unsigned long flags; 167 unsigned int hwirq; 168 int irq_line; 169 u32 mask; 170 171 hwirq = socrates_fpga_irq_to_hw(virq); 172 173 irq_line = fpga_irqs[hwirq].irq_line; 174 spin_lock_irqsave(&socrates_fpga_pic_lock, flags); 175 mask = socrates_fpga_pic_read(FPGA_PIC_IRQMASK(irq_line)) 176 & SOCRATES_FPGA_IRQ_MASK; 177 mask |= (1 << hwirq); 178 socrates_fpga_pic_write(FPGA_PIC_IRQMASK(irq_line), mask); 179 spin_unlock_irqrestore(&socrates_fpga_pic_lock, flags); 180 } 181 182 static void socrates_fpga_pic_eoi(unsigned int virq) 183 { 184 unsigned long flags; 185 unsigned int hwirq; 186 int irq_line; 187 u32 mask; 188 189 hwirq = socrates_fpga_irq_to_hw(virq); 190 191 irq_line = fpga_irqs[hwirq].irq_line; 192 spin_lock_irqsave(&socrates_fpga_pic_lock, flags); 193 mask = socrates_fpga_pic_read(FPGA_PIC_IRQMASK(irq_line)) 194 & SOCRATES_FPGA_IRQ_MASK; 195 mask |= (1 << (hwirq + 16)); 196 socrates_fpga_pic_write(FPGA_PIC_IRQMASK(irq_line), mask); 197 spin_unlock_irqrestore(&socrates_fpga_pic_lock, flags); 198 } 199 200 static int socrates_fpga_pic_set_type(unsigned int virq, 201 unsigned int flow_type) 202 { 203 unsigned long flags; 204 unsigned int hwirq; 205 int polarity; 206 u32 mask; 207 208 hwirq = socrates_fpga_irq_to_hw(virq); 209 210 if (fpga_irqs[hwirq].type != IRQ_TYPE_NONE) 211 return -EINVAL; 212 213 switch (flow_type & IRQ_TYPE_SENSE_MASK) { 214 case IRQ_TYPE_LEVEL_HIGH: 215 polarity = 1; 216 break; 217 case IRQ_TYPE_LEVEL_LOW: 218 polarity = 0; 219 break; 220 default: 221 return -EINVAL; 222 } 223 spin_lock_irqsave(&socrates_fpga_pic_lock, flags); 224 mask = socrates_fpga_pic_read(FPGA_PIC_IRQCFG); 225 if (polarity) 226 mask |= (1 << hwirq); 227 else 228 mask &= ~(1 << hwirq); 229 socrates_fpga_pic_write(FPGA_PIC_IRQCFG, mask); 230 spin_unlock_irqrestore(&socrates_fpga_pic_lock, flags); 231 return 0; 232 } 233 234 static struct irq_chip socrates_fpga_pic_chip = { 235 .name = " FPGA-PIC ", 236 .ack = socrates_fpga_pic_ack, 237 .mask = socrates_fpga_pic_mask, 238 .mask_ack = socrates_fpga_pic_mask_ack, 239 .unmask = socrates_fpga_pic_unmask, 240 .eoi = socrates_fpga_pic_eoi, 241 .set_type = socrates_fpga_pic_set_type, 242 }; 243 244 static int socrates_fpga_pic_host_map(struct irq_host *h, unsigned int virq, 245 irq_hw_number_t hwirq) 246 { 247 /* All interrupts are LEVEL sensitive */ 248 irq_to_desc(virq)->status |= IRQ_LEVEL; 249 set_irq_chip_and_handler(virq, &socrates_fpga_pic_chip, 250 handle_fasteoi_irq); 251 252 return 0; 253 } 254 255 static int socrates_fpga_pic_host_xlate(struct irq_host *h, 256 struct device_node *ct, const u32 *intspec, unsigned int intsize, 257 irq_hw_number_t *out_hwirq, unsigned int *out_flags) 258 { 259 struct socrates_fpga_irq_info *fpga_irq = &fpga_irqs[intspec[0]]; 260 261 *out_hwirq = intspec[0]; 262 if (fpga_irq->type == IRQ_TYPE_NONE) { 263 /* type is configurable */ 264 if (intspec[1] != IRQ_TYPE_LEVEL_LOW && 265 intspec[1] != IRQ_TYPE_LEVEL_HIGH) { 266 pr_warning("FPGA PIC: invalid irq type, " 267 "setting default active low\n"); 268 *out_flags = IRQ_TYPE_LEVEL_LOW; 269 } else { 270 *out_flags = intspec[1]; 271 } 272 } else { 273 /* type is fixed */ 274 *out_flags = fpga_irq->type; 275 } 276 277 /* Use specified interrupt routing */ 278 if (intspec[2] <= 2) 279 fpga_irq->irq_line = intspec[2]; 280 else 281 pr_warning("FPGA PIC: invalid irq routing\n"); 282 283 return 0; 284 } 285 286 static struct irq_host_ops socrates_fpga_pic_host_ops = { 287 .map = socrates_fpga_pic_host_map, 288 .xlate = socrates_fpga_pic_host_xlate, 289 }; 290 291 void socrates_fpga_pic_init(struct device_node *pic) 292 { 293 unsigned long flags; 294 int i; 295 296 /* Setup an irq_host structure */ 297 socrates_fpga_pic_irq_host = irq_alloc_host(pic, IRQ_HOST_MAP_LINEAR, 298 SOCRATES_FPGA_NUM_IRQS, &socrates_fpga_pic_host_ops, 299 SOCRATES_FPGA_NUM_IRQS); 300 if (socrates_fpga_pic_irq_host == NULL) { 301 pr_err("FPGA PIC: Unable to allocate host\n"); 302 return; 303 } 304 305 for (i = 0; i < 3; i++) { 306 socrates_fpga_irqs[i] = irq_of_parse_and_map(pic, i); 307 if (socrates_fpga_irqs[i] == NO_IRQ) { 308 pr_warning("FPGA PIC: can't get irq%d.\n", i); 309 continue; 310 } 311 set_irq_chained_handler(socrates_fpga_irqs[i], 312 socrates_fpga_pic_cascade); 313 } 314 315 socrates_fpga_pic_iobase = of_iomap(pic, 0); 316 317 spin_lock_irqsave(&socrates_fpga_pic_lock, flags); 318 socrates_fpga_pic_write(FPGA_PIC_IRQMASK(0), 319 SOCRATES_FPGA_IRQ_MASK << 16); 320 socrates_fpga_pic_write(FPGA_PIC_IRQMASK(1), 321 SOCRATES_FPGA_IRQ_MASK << 16); 322 socrates_fpga_pic_write(FPGA_PIC_IRQMASK(2), 323 SOCRATES_FPGA_IRQ_MASK << 16); 324 spin_unlock_irqrestore(&socrates_fpga_pic_lock, flags); 325 326 pr_info("FPGA PIC: Setting up Socrates FPGA PIC\n"); 327 } 328