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_address.h> 13 #include <linux/of_irq.h> 14 #include <linux/of_platform.h> 15 #include <linux/io.h> 16 17 /* 18 * The FPGA supports 9 interrupt sources, which can be routed to 3 19 * interrupt request lines of the MPIC. The line to be used can be 20 * specified through the third cell of FDT property "interrupts". 21 */ 22 23 #define SOCRATES_FPGA_NUM_IRQS 9 24 25 #define FPGA_PIC_IRQCFG (0x0) 26 #define FPGA_PIC_IRQMASK(n) (0x4 + 0x4 * (n)) 27 28 #define SOCRATES_FPGA_IRQ_MASK ((1 << SOCRATES_FPGA_NUM_IRQS) - 1) 29 30 struct socrates_fpga_irq_info { 31 unsigned int irq_line; 32 int type; 33 }; 34 35 /* 36 * Interrupt routing and type table 37 * 38 * IRQ_TYPE_NONE means the interrupt type is configurable, 39 * otherwise it's fixed to the specified value. 40 */ 41 static struct socrates_fpga_irq_info fpga_irqs[SOCRATES_FPGA_NUM_IRQS] = { 42 [0] = {0, IRQ_TYPE_NONE}, 43 [1] = {0, IRQ_TYPE_LEVEL_HIGH}, 44 [2] = {0, IRQ_TYPE_LEVEL_LOW}, 45 [3] = {0, IRQ_TYPE_NONE}, 46 [4] = {0, IRQ_TYPE_NONE}, 47 [5] = {0, IRQ_TYPE_NONE}, 48 [6] = {0, IRQ_TYPE_NONE}, 49 [7] = {0, IRQ_TYPE_NONE}, 50 [8] = {0, IRQ_TYPE_LEVEL_HIGH}, 51 }; 52 53 static DEFINE_RAW_SPINLOCK(socrates_fpga_pic_lock); 54 55 static void __iomem *socrates_fpga_pic_iobase; 56 static struct irq_domain *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 raw_spin_lock_irqsave(&socrates_fpga_pic_lock, flags); 84 cause = socrates_fpga_pic_read(FPGA_PIC_IRQMASK(i)); 85 raw_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 struct irq_chip *chip = irq_desc_get_chip(desc); 97 unsigned int cascade_irq; 98 99 /* 100 * See if we actually have an interrupt, call generic handling code if 101 * we do. 102 */ 103 cascade_irq = socrates_fpga_pic_get_irq(irq); 104 105 if (cascade_irq != NO_IRQ) 106 generic_handle_irq(cascade_irq); 107 chip->irq_eoi(&desc->irq_data); 108 } 109 110 static void socrates_fpga_pic_ack(struct irq_data *d) 111 { 112 unsigned long flags; 113 unsigned int irq_line, hwirq = irqd_to_hwirq(d); 114 uint32_t mask; 115 116 irq_line = fpga_irqs[hwirq].irq_line; 117 raw_spin_lock_irqsave(&socrates_fpga_pic_lock, flags); 118 mask = socrates_fpga_pic_read(FPGA_PIC_IRQMASK(irq_line)) 119 & SOCRATES_FPGA_IRQ_MASK; 120 mask |= (1 << (hwirq + 16)); 121 socrates_fpga_pic_write(FPGA_PIC_IRQMASK(irq_line), mask); 122 raw_spin_unlock_irqrestore(&socrates_fpga_pic_lock, flags); 123 } 124 125 static void socrates_fpga_pic_mask(struct irq_data *d) 126 { 127 unsigned long flags; 128 unsigned int hwirq = irqd_to_hwirq(d); 129 int irq_line; 130 u32 mask; 131 132 irq_line = fpga_irqs[hwirq].irq_line; 133 raw_spin_lock_irqsave(&socrates_fpga_pic_lock, flags); 134 mask = socrates_fpga_pic_read(FPGA_PIC_IRQMASK(irq_line)) 135 & SOCRATES_FPGA_IRQ_MASK; 136 mask &= ~(1 << hwirq); 137 socrates_fpga_pic_write(FPGA_PIC_IRQMASK(irq_line), mask); 138 raw_spin_unlock_irqrestore(&socrates_fpga_pic_lock, flags); 139 } 140 141 static void socrates_fpga_pic_mask_ack(struct irq_data *d) 142 { 143 unsigned long flags; 144 unsigned int hwirq = irqd_to_hwirq(d); 145 int irq_line; 146 u32 mask; 147 148 irq_line = fpga_irqs[hwirq].irq_line; 149 raw_spin_lock_irqsave(&socrates_fpga_pic_lock, flags); 150 mask = socrates_fpga_pic_read(FPGA_PIC_IRQMASK(irq_line)) 151 & SOCRATES_FPGA_IRQ_MASK; 152 mask &= ~(1 << hwirq); 153 mask |= (1 << (hwirq + 16)); 154 socrates_fpga_pic_write(FPGA_PIC_IRQMASK(irq_line), mask); 155 raw_spin_unlock_irqrestore(&socrates_fpga_pic_lock, flags); 156 } 157 158 static void socrates_fpga_pic_unmask(struct irq_data *d) 159 { 160 unsigned long flags; 161 unsigned int hwirq = irqd_to_hwirq(d); 162 int irq_line; 163 u32 mask; 164 165 irq_line = fpga_irqs[hwirq].irq_line; 166 raw_spin_lock_irqsave(&socrates_fpga_pic_lock, flags); 167 mask = socrates_fpga_pic_read(FPGA_PIC_IRQMASK(irq_line)) 168 & SOCRATES_FPGA_IRQ_MASK; 169 mask |= (1 << hwirq); 170 socrates_fpga_pic_write(FPGA_PIC_IRQMASK(irq_line), mask); 171 raw_spin_unlock_irqrestore(&socrates_fpga_pic_lock, flags); 172 } 173 174 static void socrates_fpga_pic_eoi(struct irq_data *d) 175 { 176 unsigned long flags; 177 unsigned int hwirq = irqd_to_hwirq(d); 178 int irq_line; 179 u32 mask; 180 181 irq_line = fpga_irqs[hwirq].irq_line; 182 raw_spin_lock_irqsave(&socrates_fpga_pic_lock, flags); 183 mask = socrates_fpga_pic_read(FPGA_PIC_IRQMASK(irq_line)) 184 & SOCRATES_FPGA_IRQ_MASK; 185 mask |= (1 << (hwirq + 16)); 186 socrates_fpga_pic_write(FPGA_PIC_IRQMASK(irq_line), mask); 187 raw_spin_unlock_irqrestore(&socrates_fpga_pic_lock, flags); 188 } 189 190 static int socrates_fpga_pic_set_type(struct irq_data *d, 191 unsigned int flow_type) 192 { 193 unsigned long flags; 194 unsigned int hwirq = irqd_to_hwirq(d); 195 int polarity; 196 u32 mask; 197 198 if (fpga_irqs[hwirq].type != IRQ_TYPE_NONE) 199 return -EINVAL; 200 201 switch (flow_type & IRQ_TYPE_SENSE_MASK) { 202 case IRQ_TYPE_LEVEL_HIGH: 203 polarity = 1; 204 break; 205 case IRQ_TYPE_LEVEL_LOW: 206 polarity = 0; 207 break; 208 default: 209 return -EINVAL; 210 } 211 raw_spin_lock_irqsave(&socrates_fpga_pic_lock, flags); 212 mask = socrates_fpga_pic_read(FPGA_PIC_IRQCFG); 213 if (polarity) 214 mask |= (1 << hwirq); 215 else 216 mask &= ~(1 << hwirq); 217 socrates_fpga_pic_write(FPGA_PIC_IRQCFG, mask); 218 raw_spin_unlock_irqrestore(&socrates_fpga_pic_lock, flags); 219 return 0; 220 } 221 222 static struct irq_chip socrates_fpga_pic_chip = { 223 .name = "FPGA-PIC", 224 .irq_ack = socrates_fpga_pic_ack, 225 .irq_mask = socrates_fpga_pic_mask, 226 .irq_mask_ack = socrates_fpga_pic_mask_ack, 227 .irq_unmask = socrates_fpga_pic_unmask, 228 .irq_eoi = socrates_fpga_pic_eoi, 229 .irq_set_type = socrates_fpga_pic_set_type, 230 }; 231 232 static int socrates_fpga_pic_host_map(struct irq_domain *h, unsigned int virq, 233 irq_hw_number_t hwirq) 234 { 235 /* All interrupts are LEVEL sensitive */ 236 irq_set_status_flags(virq, IRQ_LEVEL); 237 irq_set_chip_and_handler(virq, &socrates_fpga_pic_chip, 238 handle_fasteoi_irq); 239 240 return 0; 241 } 242 243 static int socrates_fpga_pic_host_xlate(struct irq_domain *h, 244 struct device_node *ct, const u32 *intspec, unsigned int intsize, 245 irq_hw_number_t *out_hwirq, unsigned int *out_flags) 246 { 247 struct socrates_fpga_irq_info *fpga_irq = &fpga_irqs[intspec[0]]; 248 249 *out_hwirq = intspec[0]; 250 if (fpga_irq->type == IRQ_TYPE_NONE) { 251 /* type is configurable */ 252 if (intspec[1] != IRQ_TYPE_LEVEL_LOW && 253 intspec[1] != IRQ_TYPE_LEVEL_HIGH) { 254 pr_warning("FPGA PIC: invalid irq type, " 255 "setting default active low\n"); 256 *out_flags = IRQ_TYPE_LEVEL_LOW; 257 } else { 258 *out_flags = intspec[1]; 259 } 260 } else { 261 /* type is fixed */ 262 *out_flags = fpga_irq->type; 263 } 264 265 /* Use specified interrupt routing */ 266 if (intspec[2] <= 2) 267 fpga_irq->irq_line = intspec[2]; 268 else 269 pr_warning("FPGA PIC: invalid irq routing\n"); 270 271 return 0; 272 } 273 274 static const struct irq_domain_ops socrates_fpga_pic_host_ops = { 275 .map = socrates_fpga_pic_host_map, 276 .xlate = socrates_fpga_pic_host_xlate, 277 }; 278 279 void socrates_fpga_pic_init(struct device_node *pic) 280 { 281 unsigned long flags; 282 int i; 283 284 /* Setup an irq_domain structure */ 285 socrates_fpga_pic_irq_host = irq_domain_add_linear(pic, 286 SOCRATES_FPGA_NUM_IRQS, &socrates_fpga_pic_host_ops, NULL); 287 if (socrates_fpga_pic_irq_host == NULL) { 288 pr_err("FPGA PIC: Unable to allocate host\n"); 289 return; 290 } 291 292 for (i = 0; i < 3; i++) { 293 socrates_fpga_irqs[i] = irq_of_parse_and_map(pic, i); 294 if (socrates_fpga_irqs[i] == NO_IRQ) { 295 pr_warning("FPGA PIC: can't get irq%d.\n", i); 296 continue; 297 } 298 irq_set_chained_handler(socrates_fpga_irqs[i], 299 socrates_fpga_pic_cascade); 300 } 301 302 socrates_fpga_pic_iobase = of_iomap(pic, 0); 303 304 raw_spin_lock_irqsave(&socrates_fpga_pic_lock, flags); 305 socrates_fpga_pic_write(FPGA_PIC_IRQMASK(0), 306 SOCRATES_FPGA_IRQ_MASK << 16); 307 socrates_fpga_pic_write(FPGA_PIC_IRQMASK(1), 308 SOCRATES_FPGA_IRQ_MASK << 16); 309 socrates_fpga_pic_write(FPGA_PIC_IRQMASK(2), 310 SOCRATES_FPGA_IRQ_MASK << 16); 311 raw_spin_unlock_irqrestore(&socrates_fpga_pic_lock, flags); 312 313 pr_info("FPGA PIC: Setting up Socrates FPGA PIC\n"); 314 } 315