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 static DEFINE_RAW_SPINLOCK(socrates_fpga_pic_lock); 52 53 static void __iomem *socrates_fpga_pic_iobase; 54 static struct irq_domain *socrates_fpga_pic_irq_host; 55 static unsigned int socrates_fpga_irqs[3]; 56 57 static inline uint32_t socrates_fpga_pic_read(int reg) 58 { 59 return in_be32(socrates_fpga_pic_iobase + reg); 60 } 61 62 static inline void socrates_fpga_pic_write(int reg, uint32_t val) 63 { 64 out_be32(socrates_fpga_pic_iobase + reg, val); 65 } 66 67 static inline unsigned int socrates_fpga_pic_get_irq(unsigned int irq) 68 { 69 uint32_t cause; 70 unsigned long flags; 71 int i; 72 73 /* Check irq line routed to the MPIC */ 74 for (i = 0; i < 3; i++) { 75 if (irq == socrates_fpga_irqs[i]) 76 break; 77 } 78 if (i == 3) 79 return NO_IRQ; 80 81 raw_spin_lock_irqsave(&socrates_fpga_pic_lock, flags); 82 cause = socrates_fpga_pic_read(FPGA_PIC_IRQMASK(i)); 83 raw_spin_unlock_irqrestore(&socrates_fpga_pic_lock, flags); 84 for (i = SOCRATES_FPGA_NUM_IRQS - 1; i >= 0; i--) { 85 if (cause >> (i + 16)) 86 break; 87 } 88 return irq_linear_revmap(socrates_fpga_pic_irq_host, 89 (irq_hw_number_t)i); 90 } 91 92 void socrates_fpga_pic_cascade(unsigned int irq, struct irq_desc *desc) 93 { 94 struct irq_chip *chip = irq_desc_get_chip(desc); 95 unsigned int cascade_irq; 96 97 /* 98 * See if we actually have an interrupt, call generic handling code if 99 * we do. 100 */ 101 cascade_irq = socrates_fpga_pic_get_irq(irq); 102 103 if (cascade_irq != NO_IRQ) 104 generic_handle_irq(cascade_irq); 105 chip->irq_eoi(&desc->irq_data); 106 } 107 108 static void socrates_fpga_pic_ack(struct irq_data *d) 109 { 110 unsigned long flags; 111 unsigned int irq_line, hwirq = irqd_to_hwirq(d); 112 uint32_t mask; 113 114 irq_line = fpga_irqs[hwirq].irq_line; 115 raw_spin_lock_irqsave(&socrates_fpga_pic_lock, flags); 116 mask = socrates_fpga_pic_read(FPGA_PIC_IRQMASK(irq_line)) 117 & SOCRATES_FPGA_IRQ_MASK; 118 mask |= (1 << (hwirq + 16)); 119 socrates_fpga_pic_write(FPGA_PIC_IRQMASK(irq_line), mask); 120 raw_spin_unlock_irqrestore(&socrates_fpga_pic_lock, flags); 121 } 122 123 static void socrates_fpga_pic_mask(struct irq_data *d) 124 { 125 unsigned long flags; 126 unsigned int hwirq = irqd_to_hwirq(d); 127 int irq_line; 128 u32 mask; 129 130 irq_line = fpga_irqs[hwirq].irq_line; 131 raw_spin_lock_irqsave(&socrates_fpga_pic_lock, flags); 132 mask = socrates_fpga_pic_read(FPGA_PIC_IRQMASK(irq_line)) 133 & SOCRATES_FPGA_IRQ_MASK; 134 mask &= ~(1 << hwirq); 135 socrates_fpga_pic_write(FPGA_PIC_IRQMASK(irq_line), mask); 136 raw_spin_unlock_irqrestore(&socrates_fpga_pic_lock, flags); 137 } 138 139 static void socrates_fpga_pic_mask_ack(struct irq_data *d) 140 { 141 unsigned long flags; 142 unsigned int hwirq = irqd_to_hwirq(d); 143 int irq_line; 144 u32 mask; 145 146 irq_line = fpga_irqs[hwirq].irq_line; 147 raw_spin_lock_irqsave(&socrates_fpga_pic_lock, flags); 148 mask = socrates_fpga_pic_read(FPGA_PIC_IRQMASK(irq_line)) 149 & SOCRATES_FPGA_IRQ_MASK; 150 mask &= ~(1 << hwirq); 151 mask |= (1 << (hwirq + 16)); 152 socrates_fpga_pic_write(FPGA_PIC_IRQMASK(irq_line), mask); 153 raw_spin_unlock_irqrestore(&socrates_fpga_pic_lock, flags); 154 } 155 156 static void socrates_fpga_pic_unmask(struct irq_data *d) 157 { 158 unsigned long flags; 159 unsigned int hwirq = irqd_to_hwirq(d); 160 int irq_line; 161 u32 mask; 162 163 irq_line = fpga_irqs[hwirq].irq_line; 164 raw_spin_lock_irqsave(&socrates_fpga_pic_lock, flags); 165 mask = socrates_fpga_pic_read(FPGA_PIC_IRQMASK(irq_line)) 166 & SOCRATES_FPGA_IRQ_MASK; 167 mask |= (1 << hwirq); 168 socrates_fpga_pic_write(FPGA_PIC_IRQMASK(irq_line), mask); 169 raw_spin_unlock_irqrestore(&socrates_fpga_pic_lock, flags); 170 } 171 172 static void socrates_fpga_pic_eoi(struct irq_data *d) 173 { 174 unsigned long flags; 175 unsigned int hwirq = irqd_to_hwirq(d); 176 int irq_line; 177 u32 mask; 178 179 irq_line = fpga_irqs[hwirq].irq_line; 180 raw_spin_lock_irqsave(&socrates_fpga_pic_lock, flags); 181 mask = socrates_fpga_pic_read(FPGA_PIC_IRQMASK(irq_line)) 182 & SOCRATES_FPGA_IRQ_MASK; 183 mask |= (1 << (hwirq + 16)); 184 socrates_fpga_pic_write(FPGA_PIC_IRQMASK(irq_line), mask); 185 raw_spin_unlock_irqrestore(&socrates_fpga_pic_lock, flags); 186 } 187 188 static int socrates_fpga_pic_set_type(struct irq_data *d, 189 unsigned int flow_type) 190 { 191 unsigned long flags; 192 unsigned int hwirq = irqd_to_hwirq(d); 193 int polarity; 194 u32 mask; 195 196 if (fpga_irqs[hwirq].type != IRQ_TYPE_NONE) 197 return -EINVAL; 198 199 switch (flow_type & IRQ_TYPE_SENSE_MASK) { 200 case IRQ_TYPE_LEVEL_HIGH: 201 polarity = 1; 202 break; 203 case IRQ_TYPE_LEVEL_LOW: 204 polarity = 0; 205 break; 206 default: 207 return -EINVAL; 208 } 209 raw_spin_lock_irqsave(&socrates_fpga_pic_lock, flags); 210 mask = socrates_fpga_pic_read(FPGA_PIC_IRQCFG); 211 if (polarity) 212 mask |= (1 << hwirq); 213 else 214 mask &= ~(1 << hwirq); 215 socrates_fpga_pic_write(FPGA_PIC_IRQCFG, mask); 216 raw_spin_unlock_irqrestore(&socrates_fpga_pic_lock, flags); 217 return 0; 218 } 219 220 static struct irq_chip socrates_fpga_pic_chip = { 221 .name = "FPGA-PIC", 222 .irq_ack = socrates_fpga_pic_ack, 223 .irq_mask = socrates_fpga_pic_mask, 224 .irq_mask_ack = socrates_fpga_pic_mask_ack, 225 .irq_unmask = socrates_fpga_pic_unmask, 226 .irq_eoi = socrates_fpga_pic_eoi, 227 .irq_set_type = socrates_fpga_pic_set_type, 228 }; 229 230 static int socrates_fpga_pic_host_map(struct irq_domain *h, unsigned int virq, 231 irq_hw_number_t hwirq) 232 { 233 /* All interrupts are LEVEL sensitive */ 234 irq_set_status_flags(virq, IRQ_LEVEL); 235 irq_set_chip_and_handler(virq, &socrates_fpga_pic_chip, 236 handle_fasteoi_irq); 237 238 return 0; 239 } 240 241 static int socrates_fpga_pic_host_xlate(struct irq_domain *h, 242 struct device_node *ct, const u32 *intspec, unsigned int intsize, 243 irq_hw_number_t *out_hwirq, unsigned int *out_flags) 244 { 245 struct socrates_fpga_irq_info *fpga_irq = &fpga_irqs[intspec[0]]; 246 247 *out_hwirq = intspec[0]; 248 if (fpga_irq->type == IRQ_TYPE_NONE) { 249 /* type is configurable */ 250 if (intspec[1] != IRQ_TYPE_LEVEL_LOW && 251 intspec[1] != IRQ_TYPE_LEVEL_HIGH) { 252 pr_warning("FPGA PIC: invalid irq type, " 253 "setting default active low\n"); 254 *out_flags = IRQ_TYPE_LEVEL_LOW; 255 } else { 256 *out_flags = intspec[1]; 257 } 258 } else { 259 /* type is fixed */ 260 *out_flags = fpga_irq->type; 261 } 262 263 /* Use specified interrupt routing */ 264 if (intspec[2] <= 2) 265 fpga_irq->irq_line = intspec[2]; 266 else 267 pr_warning("FPGA PIC: invalid irq routing\n"); 268 269 return 0; 270 } 271 272 static const struct irq_domain_ops socrates_fpga_pic_host_ops = { 273 .map = socrates_fpga_pic_host_map, 274 .xlate = socrates_fpga_pic_host_xlate, 275 }; 276 277 void socrates_fpga_pic_init(struct device_node *pic) 278 { 279 unsigned long flags; 280 int i; 281 282 /* Setup an irq_domain structure */ 283 socrates_fpga_pic_irq_host = irq_domain_add_linear(pic, 284 SOCRATES_FPGA_NUM_IRQS, &socrates_fpga_pic_host_ops, NULL); 285 if (socrates_fpga_pic_irq_host == NULL) { 286 pr_err("FPGA PIC: Unable to allocate host\n"); 287 return; 288 } 289 290 for (i = 0; i < 3; i++) { 291 socrates_fpga_irqs[i] = irq_of_parse_and_map(pic, i); 292 if (socrates_fpga_irqs[i] == NO_IRQ) { 293 pr_warning("FPGA PIC: can't get irq%d.\n", i); 294 continue; 295 } 296 irq_set_chained_handler(socrates_fpga_irqs[i], 297 socrates_fpga_pic_cascade); 298 } 299 300 socrates_fpga_pic_iobase = of_iomap(pic, 0); 301 302 raw_spin_lock_irqsave(&socrates_fpga_pic_lock, flags); 303 socrates_fpga_pic_write(FPGA_PIC_IRQMASK(0), 304 SOCRATES_FPGA_IRQ_MASK << 16); 305 socrates_fpga_pic_write(FPGA_PIC_IRQMASK(1), 306 SOCRATES_FPGA_IRQ_MASK << 16); 307 socrates_fpga_pic_write(FPGA_PIC_IRQMASK(2), 308 SOCRATES_FPGA_IRQ_MASK << 16); 309 raw_spin_unlock_irqrestore(&socrates_fpga_pic_lock, flags); 310 311 pr_info("FPGA PIC: Setting up Socrates FPGA PIC\n"); 312 } 313