Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
socrates_fpga_pic.c
Go to the documentation of this file.
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 
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 {
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))
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))
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))
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))
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))
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,
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 
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],
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 }