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